Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
wjainiya opened this issue Jan 3, 2025 · 0 comments
Open

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

wjainiya opened this issue Jan 3, 2025 · 0 comments

Comments

@wjainiya
Copy link

wjainiya commented Jan 3, 2025

场景:
使用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
}

以上

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant