蛋蛋星球-客户端
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 

86 рядки
2.1 KiB

  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 := 500 // 限流次数
  15. ttl := 2 // 限流过期时间
  16. ip := utils.GetIP(c.Request)
  17. //if ip != "221.4.210.167" && c.Request.Host != "127.0.0.1:4000" {
  18. // e.OutErr(c, e.ERR, "系统维护中~")
  19. // return
  20. //}
  21. // 读取token或者ip
  22. token := c.GetHeader("Authorization")
  23. // 判断是否已经超出限额次数
  24. method := c.Request.Method
  25. host := c.Request.Host
  26. uri := c.Request.URL.String()
  27. buf := make([]byte, 1024*1024*5) //TODO::5M
  28. num, _ := c.Request.Body.Read(buf)
  29. body := buf[:num]
  30. //body, _ := ioutil.ReadAll(c.Request.Body)
  31. // Write body back
  32. c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
  33. utils.FilePutContents("Limiter", utils.SerializeStr(map[string]interface{}{
  34. "uri": c.Request.URL.Path,
  35. "body": string(bytes.NewBuffer(body).Bytes()),
  36. }))
  37. //queryValue := utils.SerializeStr(c.Request.URL.Query()) //不建议开启,失去限流的意义
  38. //TODO::分布式锁阻拦(保证原子性)
  39. requestIdPrefix := fmt.Sprintf(md.DealAppLimiterRequestIdPrefix, ip)
  40. cb, err := svc.HandleLimiterDistributedLock(ip, requestIdPrefix)
  41. if err != nil {
  42. e.OutErr(c, e.ERR, err.Error())
  43. return
  44. }
  45. if cb != nil {
  46. defer cb() // 释放锁
  47. }
  48. Md5 := utils.Md5(ip + token + method + host + uri + string(body))
  49. //Md5 := utils.Md5(ip + token + method + host + uri + string(body) + queryValue)
  50. //if cache.Exists(Md5) {
  51. // c.AbortWithStatusJSON(428, gin.H{
  52. // "code": 428,
  53. // "msg": "don't repeat the request",
  54. // "data": struct{}{},
  55. // })
  56. // return
  57. //}
  58. // 2s后没返回自动释放
  59. go cache.SetEx(Md5, "0", ttl)
  60. key := "LIMITER_APP_EGG_" + ip
  61. reqs, _ := cache.GetInt(key)
  62. if reqs >= limit {
  63. c.AbortWithStatusJSON(429, gin.H{
  64. "code": 429,
  65. "msg": "too many requests",
  66. "data": struct{}{},
  67. })
  68. return
  69. }
  70. if reqs > 0 {
  71. //go cache.Incr(key)
  72. go cache.SetEx(key, reqs+1, ttl)
  73. } else {
  74. go cache.SetEx(key, 1, ttl)
  75. }
  76. c.Next()
  77. go cache.Del(Md5)
  78. }