GoLang API特定端点限流问题:错误原因及解决方案咨询
Go API特定端点限流问题分析与解决方案
错误实现失效的原因
你第二段代码的核心问题是误用了ListenAndServeTLS的根Handler参数:
http.HandleFunc是往Go默认的ServeMux(路由多路复用器)中注册路由规则,但你最终将limit(sendPushNotificationToAllTokens)作为根Handler传给ListenAndServeTLS,这直接绕过了默认ServeMux的路由匹配逻辑。- 所有请求(不管访问
/还是/notify)都会直接进入这个被限流包裹的sendPushNotificationToAllTokens函数,之前注册的/路径的Handler完全没有执行机会;同时,该函数仅处理/notify的业务逻辑,其他路径的请求也会得到错误的处理结果。
仅对/notify端点限流的可行方案
方案1:给单个Handler直接套限流中间件
利用ServeMux注册路由时,单独给/notify的Handler包裹限流逻辑,其他端点正常注册:
import ( "log" "net/http" "time" "golang.org/x/time/rate" ) var limiter = rate.NewLimiter(rate.Every(1*time.Hour/3), 1) // 限流中间件,接收HandlerFunc并返回带限流逻辑的HandlerFunc func limit(next http.HandlerFunc) http.HandlerFunc { return func(res http.ResponseWriter, req *http.Request) { if !limiter.Allow() { http.Error(res, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) return } next.ServeHTTP(res, req) } } func main() { mux := http.NewServeMux() // 正常注册无需限流的端点 mux.HandleFunc("/", createNewToken) // 给/notify端点的Handler套上限流中间件 mux.HandleFunc("/notify", limit(sendPushNotificationToAllTokens)) log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", mux)) }
方案2:在全局中间件中判断路径限流
如果需要保留全局中间件的结构,可以在中间件内部判断请求路径,仅对/notify应用限流:
import ( "log" "net/http" "time" "golang.org/x/time/rate" ) var limiter = rate.NewLimiter(rate.Every(1*time.Hour/3), 1) // 全局中间件,仅对指定路径应用限流 func limit(next http.Handler) http.Handler { return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { // 仅当请求路径为/notify时,触发限流判断 if req.URL.Path == "/notify" && !limiter.Allow() { http.Error(res, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) return } // 其他路径直接放行到下一个Handler next.ServeHTTP(res, req) }) } func main() { mux := http.NewServeMux() mux.HandleFunc("/", createNewToken) mux.HandleFunc("/notify", sendPushNotificationToAllTokens) // 将整个mux传入限流中间件,由中间件决定是否限流 log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", limit(mux))) }
内容的提问来源于stack exchange,提问作者John Harrington
相关产品推荐
相关产品推荐

