Skip to content

Commit

Permalink
feat: add cache middleware (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tohrusky authored Jul 12, 2024
1 parent cf3b3ee commit 3064a89
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 20 deletions.
4 changes: 2 additions & 2 deletions internal/middleware/cache/jwt_blacklist.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

// JWTBlacklist 检查JWT是否在黑名单中
func JWTBlacklist(redisClient *cache.Client, enableBlacklist bool) gin.HandlerFunc {
func JWTBlacklist(redisClient *cache.Client, addBlacklist bool) gin.HandlerFunc {
return func(c *gin.Context) {
// 从输入的 url 中查询 token 值
token := c.Query("token")
Expand Down Expand Up @@ -37,7 +37,7 @@ func JWTBlacklist(redisClient *cache.Client, enableBlacklist bool) gin.HandlerFu
c.Next()

// 如果启用拉黑模式,处理请求拉黑 Token
if enableBlacklist {
if addBlacklist {
err := redisClient.Set(token, "", jwt.GetJWTTokenExpiredDuration()).Err()
if err != nil {
log.Logger.Error("Error adding token to blacklist: " + err.Error())
Expand Down
35 changes: 35 additions & 0 deletions internal/middleware/cache/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package cache

import (
"github.com/TensoRaws/NuxBT-Backend/module/cache"
"github.com/TensoRaws/NuxBT-Backend/module/log"
"github.com/TensoRaws/NuxBT-Backend/module/util"
"github.com/gin-gonic/gin"
"time"
)

// Response 缓存接口响应的中间件
func Response(redisClient *cache.Client, ttl time.Duration) gin.HandlerFunc {
return func(c *gin.Context) {
// 生成缓存键,使用请求的 URL 和方法
cacheKey := c.Request.Method + ":" + c.Request.URL.String()

// 尝试从缓存中获取响应
cachedResponse, err := redisClient.Get(cacheKey).Result()
if err == nil {
// 缓存命中,直接返回缓存的响应
util.OKWithCache(c, cachedResponse)
log.Logger.Debug("Cache hit: " + cacheKey)
return
}

// 缓存未命中,调用后续的处理函数
c.Next()

// 调用结束后,将结果存入缓存
result, exists := c.Get("cache")
if exists {
redisClient.Set(cacheKey, result, ttl)
}
}
}
1 change: 1 addition & 0 deletions internal/router/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func NewAPI() *gin.Engine {
user.GET("profile/me",
middleware_cache.JWTBlacklist(cache.Clients[cache.JWTBlacklist], false),
jwt.RequireAuth(),
middleware_cache.Response(cache.Clients[cache.RespCache], 1*time.Minute),
user_service.ProfileMe,
)
}
Expand Down
9 changes: 6 additions & 3 deletions internal/service/user/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ type LoginRequest struct {
Password string `form:"password" binding:"required"`
}

type LoginResponse struct {
Token string `json:"token"`
}

// Login 用户登录 (POST /login)
func Login(c *gin.Context) {
var req LoginRequest
Expand All @@ -33,9 +37,8 @@ func Login(c *gin.Context) {
// 注册之后的下次登录成功,才会为其生成 token
token := jwt.GenerateToken(user)
// 打印相应信息和用户信息以及生成的 token 值
util.OKWithData(c, map[string]interface{}{
"user_id": user.UserID,
"token": token,
util.OKWithData(c, false, LoginResponse{
Token: token,
})
} else {
util.AbortWithMsg(c, "Invalid Username or Password")
Expand Down
2 changes: 1 addition & 1 deletion internal/service/user/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func ProfileMe(c *gin.Context) {
roles = []string{}
}

util.OKWithDataStruct(c, ProfileMeResponse{
util.OKWithData(c, true, ProfileMeResponse{
Avatar: user.Avatar,
Background: user.Background,
CreatedAt: user.CreatedAt.Format("2006-01-02 15:04:05"),
Expand Down
2 changes: 1 addition & 1 deletion internal/service/user/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func Register(c *gin.Context) {
return
}

util.OKWithDataStruct(c, RegisterDataResponse{
util.OKWithData(c, false, RegisterDataResponse{
Email: user.Email,
UserID: strconv.FormatInt(int64(user.UserID), 10),
Username: user.Username,
Expand Down
2 changes: 2 additions & 0 deletions module/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ type RDB uint8
const (
IPLimit RDB = iota
JWTBlacklist
RespCache
)

var Clients = map[RDB]*Client{
IPLimit: {},
JWTBlacklist: {},
RespCache: {},
}

type Client struct {
Expand Down
4 changes: 4 additions & 0 deletions module/cache/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,7 @@ func (c Client) SAdd(key string, members ...interface{}) *redis.IntCmd {
func (c Client) Set(key string, value interface{}, expiration time.Duration) *redis.StatusCmd {
return c.C.Set(c.Ctx, key, value, expiration)
}

func (c Client) Get(key string) *redis.StringCmd {
return c.C.Get(c.Ctx, key)
}
41 changes: 28 additions & 13 deletions module/util/gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"
"strconv"

"github.com/TensoRaws/NuxBT-Backend/module/log"
"github.com/gin-gonic/gin"
)

Expand All @@ -30,30 +31,44 @@ func OKWithMsg(c *gin.Context, ok string) {
c.JSON(http.StatusOK, resp)
}

// OKWithData 返回成功信息,携带自定义数据
func OKWithData(c *gin.Context, data map[string]interface{}) {
func AbortWithMsg(c *gin.Context, msg string) {
resp := map[string]interface{}{
"success": true,
"message": "ok",
"data": data,
"success": false,
"message": msg,
}
c.JSON(http.StatusOK, resp)
c.AbortWithStatusJSON(http.StatusOK, resp)
}

// OKWithDataStruct 返回成功信息,携带自定义数据(结构体)
func OKWithDataStruct(c *gin.Context, data interface{}) {
// OKWithData 返回成功信息,携带自定义数据(结构体)
func OKWithData(c *gin.Context, cache bool, data interface{}) {
resp := map[string]interface{}{
"success": true,
"message": "ok",
"data": data,
}
if cache {
c.Set("cache",
StructToString(
map[string]interface{}{
"success": true,
"message": "cache",
"data": data,
},
),
)
}

c.JSON(http.StatusOK, resp)
}

func AbortWithMsg(c *gin.Context, msg string) {
resp := map[string]interface{}{
"success": false,
"message": msg,
// OKWithCache 返回缓存数据,终止请求
func OKWithCache(c *gin.Context, cache string) {
var resp interface{}
err := StringToStruct(cache, &resp)
if err != nil {
log.Logger.Error(err)
return
}
c.AbortWithStatusJSON(http.StatusOK, resp)
c.JSON(http.StatusOK, resp)
c.Abort()
}
6 changes: 6 additions & 0 deletions module/util/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,9 @@ func StructToString(s interface{}) string {
v, _ := sonic.Marshal(s)
return string(v)
}

// StringToStruct 字符串转结构体
func StringToStruct(str string, s interface{}) error {
// return json.Unmarshal([]byte(str), s)
return sonic.Unmarshal([]byte(str), s)
}

0 comments on commit 3064a89

Please sign in to comment.