在实际工作中,有时候需要对提供的api实现数据缓存,缓解数据压力.一般的做饭就是先查询是否有缓存,如果有则用缓存,没有就查询数据库。
但是每个方法都去实现一遍有点累,现考了到在中间件实现。
在中间件根据请求参数和api地址作为缓存key, 如果有缓存key,直接返回,没有则放行,从response中拿结果。
在gin中的response其实是gin.context.writer,为实现这个功能,需要重新writer方法,
代码如下:
type responseWriter struct {
gin.ResponseWriter
b *bytes.Buffer // 记录返回的数据
}
// 重写Writer
func (w responseWriter) Write(b []byte) (int, error) {
w.b.Write(b)
return w.ResponseWriter.Write(b)
}
创建一个中间件:
func ApiCache() gin.HandlerFunc {
return func(c *gin.Context) {
// 只缓存get的请求
if c.Request.Method != http.MethodGet {
c.Next()
return
}
requestUri := c.Request.RequestURI
params := make([]string, 0)
for _, v := range c.Params {
params = append(params, fmt.Sprintf("%s:%s", v.Key, v.Value))
}
if len(params) > 0 {
requestUri += "&" + strings.Join(params, "&")
}
// 生成缓存key
cacheKey := utils.SimpleMd5(requestUri)
htmlFile := filepath.Join("./cache", cacheKey)
if utils.FileIsExisted(htmlFile) {
c.File(htmlFile)
c.AbortWithStatus(http.StatusOK) // 一定要abort,不然还会继续执行next()
return
}
// 使用重写的writer
writer := responseWriter{
c.Writer,
bytes.NewBuffer([]byte{}),
}
c.Writer = writer
c.Next()
// 保存缓存
if c.Writer.Status() == http.StatusOK {
utils.WriteFile2(htmlFile, writer.b.Bytes())
}
}
}
最后就能实现根据api缓存了.