BitzOrcas 使用 ASP.NET Core 内置限流,配合租户 + 调用方分区策略。每个租户/调用方对获得独立的计数桶,防止应用调用方共享匿名桶。
三种策略
| 策略 | 算法 | 窗口 | 用途 |
|---|---|---|---|
userPolicy | 令牌桶 | 1 分钟 | 通用 REST API 端点 |
sensitivePolicy | 滑动窗口 | 1 分钟 | 登录、OTP、密码重置 |
fixedPolicy | 固定窗口 | 1 分钟 | 内部/低频服务 |
分区键格式
{tenant_id}:{user_id|client_id}这确保应用调用方(有 client_id 但无 user_id)被正确分区,而非全部落入”匿名”桶。
策略参数
userPolicy(令牌桶)
new TokenBucketRateLimiterOptions{ TokenLimit = 2, TokensPerPeriod = 2, ReplenishmentPeriod = TimeSpan.FromMinutes(1), QueueLimit = 0, AutoReplenishment = true,}每分钟 2 个请求,无排队。
sensitivePolicy(滑动窗口)
new SlidingWindowRateLimiterOptions{ Window = TimeSpan.FromMinutes(1), SegmentsPerWindow = 4, PermitLimit = 5, QueueLimit = 0,}每分钟 5 个请求——滑动窗口防止边界突发攻击。
fixedPolicy(固定窗口)
new FixedWindowRateLimiterOptions{ Window = TimeSpan.FromMinutes(1), PermitLimit = 10, AutoReplenishment = true,}每分钟 10 个请求——简单可预测,适用于内部服务。
429 响应
所有限流请求返回 RFC 9457 ProblemDetails:
{ "type": "https://docs.bitzsoft.com/problems/rate-limit-exceeded", "title": "Too Many Requests", "status": 429, "detail": "Rate limit exceeded.", "errorCode": "RateLimit.Exceeded", "retryAfter": 60}包含 HTTP 头:
Retry-After: 60X-RateLimit-Remaining: 0(可用时)
端点中使用
app.MapPost("/api/notes", async (...) => ...) .RequireRateLimiting("userPolicy");
app.MapPost("/api/auth/login", async (...) => ...) .RequireRateLimiting("sensitivePolicy");中间件顺序
限流中间件放在管道中授权之后:
ExceptionHandler → CorrelationId → Auth → DelegationToken→ TenantResolution → Audit → Authorization → RateLimiter → Endpoints生产环境考量
对于多实例部署,考虑:
- Redis DistributedRateLimiter — 跨实例共享计数器
- 网关级限流 — YARP/Envoy/Nginx 在到达 API 之前限流
- 每租户限流计划 — 从计费订阅配置可配限制