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

mw_limiter.go 2.1 KiB

1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1週間前
1ヶ月前
1週間前
6日前
1ヶ月前
6日前
1ヶ月前
1週間前
1ヶ月前
6日前
6日前
6日前
1ヶ月前
1週間前
1ヶ月前
1ヶ月前
1ヶ月前
1週間前
1ヶ月前
1ヶ月前
1ヶ月前
1週間前
1ヶ月前
1ヶ月前
1ヶ月前
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  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. }