这篇文章将为大家详细讲解有关利用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