为了账号安全,请及时绑定邮箱和手机立即绑定

基于主机地址的限速http请求

基于主机地址的限速http请求

Go
aluckdog 2022-05-18 14:43:36
我使用 Go 开发了一个 HTTP 服务器。现在我想实现一个速率限制器,这样我就可以检查来自特定 IP 的 HTTP 请求是否在 1 分钟内发送超过 10 个 HTTP 请求,我可以将该 IP 放入阻止列表中一段时间,比如(1 小时) 并且与此同时,同一订阅者在他/她处于阻塞期时正在发送请求,我将从 HTTP 服务器发送 429 错误响应。我为此编写了一个代码,但在此能够阻止 IP 地址,但它会在 1 小时后解除对所有 IP 的阻止。我期待先到先解锁。Package mainimport (    "log"    "net/http"    "strings"    "time")func main() {    fs := http.FileServer(http.Dir("./html/"))    http.Handle("/", fs)    log.Println("Listening..")    go clearLastRequestsIPs()    go clearBlockedIPs()    err := http.ListenAndServe(":8080", middleware(nil))    if err != nil {        log.Fatalln(err)    }}// Stores last requests IPsvar lastRequestsIPs []string// Block IP for 1 hoursvar blockedIPs []stringfunc middleware(next http.Handler) http.Handler {    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        ipAddr := strings.Split(r.RemoteAddr, ":")[0]        if existsBlockedIP(ipAddr) {            http.Error(w, "", http.StatusTooManyRequests)            return        }        // how many requests the current IP made in last 5 mins        requestCounter := 0        for _, ip := range lastRequestsIPs {            if ip == ipAddr {                requestCounter++            }        }        if requestCounter >= 1000 {            blockedIPs = append(blockedIPs, ipAddr)            http.Error(w, "", http.StatusTooManyRequests)            return        }        lastRequestsIPs = append(lastRequestsIPs, ipAddr)        if next == nil {            http.DefaultServeMux.ServeHTTP(w, r)            return        }        next.ServeHTTP(w, r)    })}func existsBlockedIP(ipAddr string) bool {    for _, ip := range blockedIPs {        if ip == ipAddr {            return true        }    }    return false}func existsLastRequest(ipAddr string) bool {    for _, ip := range lastRequestsIPs {        if ip == ipAddr {            return true        }    }    return false}
查看完整描述

2 回答

?
HUWWW

TA贡献1874条经验 获得超12个赞

你可以使用一些像这样的中间件:


type Limiter struct {

    ipCount map[string]int

    sync.Mutex

}


var limiter Limiter

func init() {

    limiter.ipCount = make(map[string]int)

}


func limit(next http.Handler) http.Handler {

  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

    // Get the IP address for the current user.

    ip, _, err := net.SplitHostPort(r.RemoteAddr)

    if err != nil {

      log.Println(err.Error())

      http.Error(w, "Internal Server Error", http.StatusInternalServerError)

      return

    }


    // Get the # of times the visitor has visited in the last 60 seconds

    limiter.Lock()

    count, ok := limiter.ipCount[ip]

    if !ok {

        limiter.ipCount[ip] = 0

    }

    if count > 10 {

      limiter.Unlock()

      http.Error(w, http.StatusText(429), http.StatusTooManyRequests)

      return

    } else {

        limiter.ipCount[ip]++

    }

    time.AfterFunc(time.Second * 60, func() {

        limiter.Lock()

        limiter.ipCount[ip]--

        limiter.Unlock()

    })

    if limiter.ipCount[ip] == 10 {

        // set it to 20 so the decrement timers will only decrease it to

        // 10, and they stay blocked until the next timer resets it to 0

        limiter.ipCount[ip] = 20

        time.AfterFunc(time.Hour, func() {

            limiter.Lock()

            limiter.ipCount[ip] = 0

            limiter.Unlock()

        })

    }

    limiter.Unlock()

    next.ServeHTTP(w, r)

  })

}    



查看完整回答
反对 回复 2022-05-18
?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞

rate.NewLimiter()从 golang.org/x/time/rate 包中使用。



查看完整回答
反对 回复 2022-05-18
  • 2 回答
  • 0 关注
  • 107 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信