限流应分层识别真实用户与脚本而非激进封禁。按UA、Cookie、Referer等特征区分对象,登录接口按账号限流,静态资源放宽burst,敏感接口设小burst并排队,支持动态降级、白名单及日志监控闭环优化。

限流策略太激进,容易把真实用户当成攻击者拦掉。关键不是“限得更死”,而是让规则更贴合真实访问行为——识别谁是人、谁是脚本,再分层控制。
按访问特征区分限流对象
别只用 IP 一刀切。真实用户常有以下特点:带浏览器 UA、有 Cookie、走 HTTPS、请求路径分散、有 Referer。而刷接口的脚本往往 UA 简单(如 curl)、无 Cookie、集中打同一个 URL。
- 对登录、验证码等敏感接口,优先用 $http_cookie 或 $http_x_user_id 做限流键,已登录用户按账号限,未登录才回落到 IP
- 用 $request_uri + $binary_remote_addr 组合定义 zone,避免不同接口共用同一桶导致误伤(例如 /login 被刷,不影响 /static/css)
- 加一层轻量判断:在 location 中用 if 拦截明显异常请求(如 UA 为空、请求头含 python-requests),直接 return 403,不进限流逻辑
合理设置 burst 和排队行为
burst 不是越大越好,也不是越小越安全。它本质是给“合法突发”留的缓冲空间,比如页面加载时并发请求 JS/CSS/图片。
- 静态资源(/static/、/img/)可设 burst=50 nodelay,允许快速加载,但 rate 放宽(如 100r/s)
- 登录接口建议 burst=3~5,不加 nodelay,让超限请求排队等待 1–2 秒再响应,既防暴力破解,又避免瞬间 503 把用户吓退
- 对需要友好提示的场景(如短信发送),去掉 nodelay 后配合 error_page 429,返回 JSON 提示:“操作太频繁,请 60 秒后重试”
动态降级与白名单机制
高峰期或运维时段,可以临时放宽;可信来源(如内网、合作方)应绕过基础限流。
- 用 map 指令构建动态限流速率:map $remote_addr $req_rate { default "1r/s"; ~^192\.168\. "10r/s"; },然后 rate=$req_rate
- 结合 geo 模块或 real_ip 模块,对 CDN 回源 IP、公司出口 IP 设置独立 zone,rate 提高 5–10 倍
- 对健康检查路径(如 /healthz)或监控探针,用 location = /healthz { limit_req off; } 完全关闭限流
监控反馈闭环,避免盲目调参
限流不是配完就完事。要持续看哪些 IP/URI 被大量拦截,再反推规则是否合理。
- 开启 Nginx 日志变量:$limit(触发限流为 1)、$limit_key(被限的具体键值),写入 access_log 方便分析
- 用 log_format 记录被限请求的 UA、Referer、$request_time,排查是否误杀搜索爬虫或移动端 WebView
- 定期统计 503/429 错误占比,若超过 0.5%,说明 burst 太小或 rate 过严,需调整


















