Skip to content

使用redis缓存做中间层的建议 #9

@wjainiya

Description

@wjainiya

场景:
使用redis缓存用户的请求结果,return c.JSON(http.StatusOK, commom.SuccessPayload(data))

做法:
在router 层面使用 redis 缓存的handlerFunc, 伪代码
r.GET("/redis", commom.CacheBefore(), db2.RedisTest, commom.CacheAfter())

解释:
根据用户的请求参数,请求uri, 做md5计算得到 key
CacheBefore(), 判断是否有key 缓存,有则返回, 无则注入request param, redis_cache=key
CacheAfter(),将db2.RedisTest 返回的Response 结果 存入redis

修改:
源码中 Context.go ->Next() 方法不使用if c.w.Written(){ break } 方法中断, 因为 hanlders 中可能有多个json 返回,这样会提前结束。

  1. Next() 方法增加一个标志位 if c.w.Break() {break} 。
  2. response_overide.go:
    a. ResponseWriter 增加 Break() , 用于判断是否要在 Next()中随时返回
    b. responseWriter 增加 body *bytes.Buffer ; breakNext bool 两个参数,breakNext用于 c.w.Break() , body用于拦截前面hander返回的json 数据,写入redis.

补充:

func CacheBefore() yee.HandlerFunc {
	return func(c yee.Context) (err error) {
		urI := c.RequestURI()
		if (strings.Contains(urI, "/api/v2/redis") || strings.Contains(urI, "/api/v2/fetch/idc") || strings.Contains(urI, "/api/v2/fetch/")) && c.Request().Method == http.MethodGet {
			// 角色
			_, role := lib.JwtParse(c)

			// 请求参数
			cacheKey := StringToMd5(urI + role)

			if val, err := lib.HasKey(cacheKey); err == nil {
				fmt.Printf("return CacheBefore value , cacheKey: %s", cacheKey)

				return c.JSON(http.StatusOK, val, true)
			} else {
				return c.JSON(http.StatusInternalServerError, err.Error(), true)
			}
			// 标记将结果缓存到 redis, key=yea_cache , value=cacheKey
			c.InjectQueryParam(model.RedisKey, cacheKey)
			fmt.Printf("CacheBefore need redis cacheKey: %s\n", cacheKey)
		}
		return
	}
}

func CacheAfter() yee.HandlerFunc {
	return func(c yee.Context) (err error) {
		header := c.Response().Header().Get(yee.HeaderContentType)
		cacheKey := c.QueryParam(model.RedisKey)
		if cacheKey != "" && header == yee.MIMEApplicationJSONCharsetUTF8 {
			body := c.Response().Body()
			fmt.Printf("CacheAfter write data into redis : %+v \n", body)
			err = model.RDB().Set(context.Background(), cacheKey, body, model.DefaultCacheTime).Err()
			if err != nil {
				fmt.Printf("could not set data in Redis: %v \n", err)
				return c.JSON(http.StatusOK, ERR_COMMON_MESSAGE(err))
			}
			fmt.Println("RedisTest Data stored in Redis OK !")
		}

		return
	}
}

// context.go 
func (c *context) JSON(code int, i interface{}, args ...interface{}) (err error) {
	if !c.writermem.Written() {
		enc := json.NewEncoder(c.w)
		c.writeContentType(MIMEApplicationJSONCharsetUTF8)
		c.w.WriteHeader(code)
		if len(args) > 0 {
			if flag, ok := args[0].(bool); ok {
				c.Response().InjectBreak(flag)
			}
		}
		return enc.Encode(i)
	}
	return
}

以上

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions