1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
mux.Use(middleware.LimitRate)
package middleware
import ( "crypto/md5" "encoding/hex" "github.com/garyburd/redigo/redis" "jiagu-user-service/internal/captcha/common" "net/http" "sync" )
type RequestLimitService struct { Interval int MaxCount int }
func NewRequestLimitService(interval int, maxCnt int) *RequestLimitService { if common.IsDev() { interval = interval / 10 maxCnt = maxCnt / 10 } reqLimit := &RequestLimitService{ Interval: interval, MaxCount: maxCnt, } return reqLimit }
func (reqLimit *RequestLimitService) IsAvailable(r *http.Request) bool { _ = r.ParseForm() ip := r.RemoteAddr pn := r.Form.Get("pn") path := r.RequestURI if path == common.API_PATH_V1_AUTH { limitRateKey := Md5V(ip + pn) c := reqLimit.GetLimitCountCache(common.REDIS_LIMIT_RATE_PREFIX + limitRateKey) return c < reqLimit.MaxCount } return true
}
func (reqLimit *RequestLimitService) GetLimitCountCache(limitRateKeyCount string) int { redisCw := RedisW.Get() redisCr := RedisW.Get() defer redisCr.Close() defer redisCw.Close()
var c = 1 isKeyEx, err := redis.Bool(redisCr.Do("EXISTS", limitRateKeyCount))
CheckErr(err, false)
if isKeyEx { _, _ = redisCw.Do("INCR", limitRateKeyCount) c, _ = redis.Int(redisCr.Do("GET", limitRateKeyCount)) } else { _, err = redisCw.Do("SET", limitRateKeyCount, 1, "EX", reqLimit.Interval) CheckErr(err, false) } return c }
var RequestLimit = NewRequestLimitService(common.REDIS_LIMIT_RATE_EXPIRE, common.API_LIMIT_RATE_NUM)
func Md5V(str string) string { h := md5.New() h.Write([]byte(str)) return hex.EncodeToString(h.Sum(nil)) } func LimitRate(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if RequestLimit.IsAvailable(r) { next.ServeHTTP(w, r) } else { http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) return } }) }
|