蛋蛋星球-客户端
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

mw_limiter.go 1.8 KiB

4日前
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package mw
  2. import (
  3. "applet/app/e"
  4. "applet/app/md"
  5. "applet/app/svc"
  6. "applet/app/utils"
  7. "applet/app/utils/cache"
  8. "bytes"
  9. "fmt"
  10. "github.com/gin-gonic/gin"
  11. "io/ioutil"
  12. )
  13. func Limiter(c *gin.Context) {
  14. limit := 200 // 限流次数
  15. ttl := 2 // 限流过期时间
  16. ip := c.ClientIP()
  17. // 读取token或者ip
  18. token := c.GetHeader("Authorization")
  19. mid := c.GetString("mid")
  20. // 判断是否已经超出限额次数
  21. method := c.Request.Method
  22. host := c.Request.Host
  23. uri := c.Request.URL.String()
  24. buf := make([]byte, 5120*10)
  25. num, _ := c.Request.Body.Read(buf)
  26. body := buf[:num]
  27. // Write body back
  28. c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
  29. //queryValue := utils.SerializeStr(c.Request.URL.Query()) //不建议开启,失去限流的意义
  30. //TODO::分布式锁阻拦(保证原子性)
  31. requestIdPrefix := fmt.Sprintf(md.DealAppLimiterRequestIdPrefix, mid, ip)
  32. cb, err := svc.HandleLimiterDistributedLock(mid, ip, requestIdPrefix)
  33. if err != nil {
  34. e.OutErr(c, e.ERR, err.Error())
  35. return
  36. }
  37. if cb != nil {
  38. defer cb() // 释放锁
  39. }
  40. Md5 := utils.Md5(ip + token + method + host + uri + string(body))
  41. //Md5 := utils.Md5(ip + token + method + host + uri + string(body) + queryValue)
  42. if cache.Exists(Md5) {
  43. c.AbortWithStatusJSON(428, gin.H{
  44. "code": 428,
  45. "msg": "don't repeat the request",
  46. "data": struct{}{},
  47. })
  48. return
  49. }
  50. // 2s后没返回自动释放
  51. go cache.SetEx(Md5, "0", ttl)
  52. key := "LIMITER_EGG_APP" + ip
  53. reqs, _ := cache.GetInt(key)
  54. if reqs >= limit {
  55. c.AbortWithStatusJSON(429, gin.H{
  56. "code": 429,
  57. "msg": "too many requests",
  58. "data": struct{}{},
  59. })
  60. return
  61. }
  62. if reqs > 0 {
  63. //go cache.Incr(key)
  64. go cache.SetEx(key, reqs+1, ttl)
  65. } else {
  66. go cache.SetEx(key, 1, ttl)
  67. }
  68. c.Next()
  69. go cache.Del(Md5)
  70. }