介绍

这篇文章将为大家详细讲解有关利用golang怎么对接口IP进行限流,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

增加中间件

可以选择普通模式和LUA脚本模式,建议选择普通模式,实际上不需要控制的那么精确。

package 中间件)   import  (   “;github.com/gin-gonic/gin"   “strconv"   “time"   “voteapi/pkg/app/response"   “voteapi/pkg/gredis"   “voteapi/pkg/util"   )   const  IP_LIMIT_NUM_KEY =,“ipLimit: ipLimitNum"   const  IP_BLACK_LIST_KEY =,“ipLimit: ipBlackList"   var  prefix =,“{网关}“;   时间=var  delaySeconds  int64  60,,//,观察时间跨度,秒   时间=var  maxAttempts  int64  10000,//,限制请求数   var  blackSeconds  int64 =, 0,,//,封禁时长,秒,0 -不封禁   func  GateWayPlus (), gin.HandlerFunc  {   return  func (c  * gin.Context), {   path :=, c.FullPath ()   clientIp :=, c.ClientIP ()//,复述,配置集群时必须   param :=, (map [string]字符串)   参数(“path"),=,路径   参数(“clientIp"),=clientIp   if 主要!(参数),{   c.Abort ()   response.JsonResponseError (c,“当前IP请求过于频繁,暂时被封禁~“)   }   }   }   func 主要(param  map [string]字符串),bool  {//,预知的IP黑名单   var  blackList []字符串   if  util.InStringArray(参数(“clientIp"),黑名单),{   return 假   }//,预知的IP白名单   var  whiteList []字符串   if  util.InStringArray(参数(“clientIp"),白名单),{   return 假   }   blackKey :=, prefix  +,“:“, + IP_BLACK_LIST_KEY   limitKey :=, prefix  +,“:“, + IP_LIMIT_NUM_KEY   .Unix curr :=, time.Now () ()   item :=, util.Md5(参数(“path"), +,“|”, +,参数[“clientIp"])   return 正常(blackKey, limitKey,,,,咕咕叫)   }//,普通模式   func 正常(字符串,blackKey  limitKey 字符串,item 字符串,time  int64), (res  bool), {   if  blackSeconds 祝辞,0,{   超时,_ :=, gredis.RawCommand (“HGET",, blackKey,,项目)   if  timeout  !=, nil  {   ,,_ :=, strconv.Atoi (string(超时([]uint8)))   if  int64(),祝辞,time  {//,未解封   return 假   }//,已解封,移除黑名单   gredis.RawCommand (“HDEL", blackKey,,项目)   }   }   l, _ :=, gredis.RawCommand (“HGET",, limitKey,,项目)   if  l  !=, nil  {   最后,_ :=, strconv.Atoi (string (l ([] uint8)))   if  int64(去年),祝辞=,maxAttempts  {   return 假   }   }   num, _ :=, gredis.RawCommand (“HINCRBY",, limitKey,,,, 1)   if  ttl, _ :=, gredis.TTLKey (limitKey);, ttl ==, int64 (1), {   gredis.Expire (limitKey, int64 (delaySeconds))   }   if  num。(int64),祝辞=,maxAttempts ,,, blackSeconds 祝辞,0,{//,加入黑名单   gredis.RawCommand (“HSET", blackKey,,,,时间+ blackSeconds)//,删除记录   gredis.RawCommand (“HDEL", limitKey,,项目)   }   return 真正的   }//,LUA脚本模式//,支持复述,集群部署   func  luaScript(字符串,blackKey  limitKey 字符串,item 字符串,time  int64), (res  bool), {   script :=,   local  blackSeconds =,当时(ARGV [5])   如果(blackSeconds 祝辞,0)   然后   local 才能;timeout =, redis.call (& # 39; hget& # 39;,,键[1],ARGV [1])   如果才能(timeout  ~=,假)   然后才能   ,,,如果(当时(超时),祝辞,当时(ARGV [2]))   ,,,   ,,,,,return 错误的   ,才能结束   ,,,redis.call (& # 39; hdel& # 39;,,键[1],ARGV [1])   ,结束   结束   local  last =, redis.call (& # 39; hget& # 39;,,键[2],ARGV [1])   如果(last  ~=, false 以及当时(去年),祝辞=,当时(ARGV [3]))   然后   return 才能;错误的   结束   local  num =, redis.call (& # 39; hincrby& # 39;,,键[2],ARGV [1],, 1)   local  ttl =, redis.call (& # 39; ttl # 39;,,键[2])   如果(ttl ==, 1)   然后   redis.call才能(& # 39;到期# 39;,,键[2],ARGV [4])   结束   如果当时(num),祝辞=,当时(ARGV[3]),以及blackSeconds 祝辞,0)   then    redis.call才能(& # 39;hset& # 39;,,键[1],ARGV [1],, ARGV [2], +, ARGV [5])   redis.call才能(& # 39;hdel& # 39;,,键[2],ARGV [1])   结束   return 真正的   ”   因此,,err :=, gredis.RawCommand (“EVAL",,脚本,,2,,blackKey,, limitKey,,,,,, maxAttempts,, delaySeconds,, blackSeconds)   if  err  !=, nil  {   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null