2026-08-15 14:38:14 +08:00
package middleware
2026-08-15 13:30:35 +08:00
2026-08-27 00:57:49 +08:00
// 本文件提供带 metrics 埋点的限流 / 并发中间件版本。
// 相比 router 实际使用的实现,本版本额外做了:
// - 加 metrics 埋点(限流拒绝 / 并发拒绝计数)
// - 仅对 /v1/ 下的业务请求生效,监控路径(/health /metrics /dashboard)不消耗配额
2026-08-15 13:30:35 +08:00
import (
"log"
"net/http"
2026-08-16 18:50:33 +08:00
"strings"
2026-08-15 13:30:35 +08:00
"github.com/volcano-tts/tts-api/metrics"
)
2026-08-27 00:57:49 +08:00
// RateLimitWithMetrics 是限流中间件,带埋点 + 路径过滤。
2026-08-15 13:30:35 +08:00
func RateLimitWithMetrics ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2026-08-16 18:50:33 +08:00
// 仅对 /v1/ 下的业务请求限流,/health /metrics /dashboard 等监控路径不限流
if ! strings . HasPrefix ( r . URL . Path , "/v1/" ) {
next . ServeHTTP ( w , r )
return
}
2026-08-15 13:30:35 +08:00
clientIP := GetClientIP ( r )
if ! GlobalRateLimiter . Allow ( clientIP ) {
log . Printf ( "警告: 已超过IP速率限制,拒绝请求 - 客户端IP: %s" , clientIP )
SendJSONError ( w , http . StatusTooManyRequests , "Rate limit exceeded. Please try again later." , "rate_limit_error" , "rate_limit_exceeded" )
return
}
next . ServeHTTP ( w , r )
})
}
2026-08-27 00:57:49 +08:00
// ConcurrencyLimitWithMetrics 是并发控制中间件,带埋点 + 路径过滤。
2026-08-15 13:30:35 +08:00
func ConcurrencyLimitWithMetrics ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2026-08-16 18:50:33 +08:00
// 仅对 /v1/ 下的业务请求统计并发和加锁,监控路径不占用并发槽位
if ! strings . HasPrefix ( r . URL . Path , "/v1/" ) {
next . ServeHTTP ( w , r )
return
}
2026-08-15 13:30:35 +08:00
select {
case ConcurrencySem <- struct {}{}:
metrics . ConcurrencyActive . Inc ( nil )
defer func () {
<- ConcurrencySem
metrics . ConcurrencyActive . Dec ( nil )
}()
next . ServeHTTP ( w , r )
default :
metrics . ConcurrencyRejected . Inc ( nil )
log . Printf ( "警告: 已达到最大并发请求数限制,拒绝请求 - 客户端IP: %s" , GetClientIP ( r ))
SendJSONError ( w , http . StatusServiceUnavailable , "Server is busy, maximum concurrent requests reached. Please try again later." , "concurrency_limit_error" , "max_concurrent_requests" )
return
}
})
}