|
- package mw
-
- import (
- "applet/app/e"
- "applet/app/md"
- "applet/app/svc"
- "applet/app/utils"
- "applet/app/utils/cache"
- "bytes"
- "fmt"
- "github.com/gin-gonic/gin"
- "io/ioutil"
- )
-
- func Limiter(c *gin.Context) {
- limit := 200 // 限流次数
- ttl := 2 // 限流过期时间
- ip := c.ClientIP()
- // 读取token或者ip
- token := c.GetHeader("Authorization")
- mid := c.GetString("mid")
- // 判断是否已经超出限额次数
- method := c.Request.Method
- host := c.Request.Host
- uri := c.Request.URL.String()
-
- buf := make([]byte, 5120*10)
- num, _ := c.Request.Body.Read(buf)
- body := buf[:num]
- // Write body back
- c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
- //queryValue := utils.SerializeStr(c.Request.URL.Query()) //不建议开启,失去限流的意义
-
- //TODO::分布式锁阻拦(保证原子性)
- requestIdPrefix := fmt.Sprintf(md.DealAppLimiterRequestIdPrefix, mid, ip)
- cb, err := svc.HandleLimiterDistributedLock(mid, ip, requestIdPrefix)
- if err != nil {
- e.OutErr(c, e.ERR, err.Error())
- return
- }
- if cb != nil {
- defer cb() // 释放锁
- }
-
- Md5 := utils.Md5(ip + token + method + host + uri + string(body))
- //Md5 := utils.Md5(ip + token + method + host + uri + string(body) + queryValue)
- if cache.Exists(Md5) {
- c.AbortWithStatusJSON(428, gin.H{
- "code": 428,
- "msg": "don't repeat the request",
- "data": struct{}{},
- })
- return
- }
-
- // 2s后没返回自动释放
- go cache.SetEx(Md5, "0", ttl)
-
- key := "LIMITER_EGG_APP" + ip
- reqs, _ := cache.GetInt(key)
- if reqs >= limit {
- c.AbortWithStatusJSON(429, gin.H{
- "code": 429,
- "msg": "too many requests",
- "data": struct{}{},
- })
- return
- }
- if reqs > 0 {
- //go cache.Incr(key)
- go cache.SetEx(key, reqs+1, ttl)
- } else {
- go cache.SetEx(key, 1, ttl)
- }
- c.Next()
- go cache.Del(Md5)
- }
|