限流是政策,不是数字
先选维度:按 IP、API key、用户还是租户。按 IP 简单,但会惩罚共享 NAT 后的用户;按 key 需要认证和密钥轮换。对昂贵或未认证路由施加更严格限制,并让健康检查不进入限流器。
内存实现只是起点
基于 Map 的限流器在单进程内正确。多实例位于负载均衡器后时,每个实例各自计数,客户端可能获得 N 倍预期限额。服务水平扩展时,应把计数器移到 Redis 或在网关执行限流。
清理很重要。按 IP 建键的 Map 在扫描流量下会无限增长。定期清扫过期桶,限制 map 大小,并考虑有界 LRU。攻击下会泄漏内存的限流器是新的漏洞。
返回有用的响应
返回 429,而不是 500。包含 Retry-After 和简短响应体。不要泄露内部配额或其他客户端信息。按采样率记录限流键和路由,隐私规则要求最小化时不要无限期记录原始 IP。
app.use(rateLimit({ windowMs: 60_000, max: 60 }));
验证边界
预期结果:窗口内恰好 60 个请求成功,第 61 个返回 429 且 Retry-After 为正数。用突发命令确认,并检查计数器按客户端地址而非代理地址建键。限流从不触发,或对所有客户端同时触发,说明键或 trust-proxy 配置有误。