1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| func limiting() gin.HandlerFunc { return func(c *gin.Context) { type limitingConfig struct { Time time.Duration Value uint16 }
var limitingList = make(map[string]limitingConfig)
limitingList["GET_/user"] = limitingConfig{ Time: time.Minute * 1, Value: 10, }
routeKey := fmt.Sprintf("%s_%s", c.Request.Method, c.FullPath())
limitingInfo, exists := limitingList[routeKey]
if exists == false { c.Next()
return }
identification := func(c *gin.Context) string { return c.ClientIP()
}(c)
timeIndex := float64(time.Now().Unix()) / limitingInfo.Time.Seconds()
cacheKey := fmt.Sprintf("%s:%s:%d", c.Request.Method, sha1Value(c.FullPath()), int64(math.Floor(timeIndex)))
rdb := redis.NewClient(&redis.Options{ Addr: "redis.hongfs.cn", })
res, err := rdb.HIncrBy(context.Background(), cacheKey, identification, 1).Result()
if err != nil { log.Println("Redis 处理异常:" + err.Error())
c.AbortWithStatus(http.StatusInternalServerError)
return }
if res == 1 { rdb.Expire(context.Background(), cacheKey, time.Duration(limitingInfo.Time.Seconds()+1)) }
c.Writer.Header().Set("X-Ratelimit-Limit", strconv.Itoa(int(limitingInfo.Value))) c.Writer.Header().Set("X-Ratelimit-Reset", strconv.FormatInt(int64(timeIndex+1)*int64(limitingInfo.Time.Seconds()), 10))
if res > int64(limitingInfo.Value) { c.Writer.Header().Set("X-Ratelimit-Remaining", "0")
c.AbortWithStatus(http.StatusTooManyRequests)
return }
c.Writer.Header().Set("X-Ratelimit-Remaining", strconv.FormatInt(int64(limitingInfo.Value)-res, 10))
c.Next() } }
|