如何在NGINX中仅对成功请求(HTTP 200)开启速率限制?
仅对返回200的请求开启NGINX速率限制的实现方案
当然可以实现这个需求!你的场景是联系表单邮件发送,只需要限制成功提交(后端返回HTTP 200)的请求频率,失败请求不做限制,这需要调整NGINX的限速触发逻辑——默认的limit_req是请求到达时就统计,咱们得改成根据后端返回的状态码来决定是否计入限速统计。
核心思路
利用NGINX的map指令自定义一个变量,只有当后端返回200状态码时,这个变量才会带上客户端的IP地址;其他状态码下变量为空。然后基于这个变量创建限速区域,这样只有成功请求才会被纳入限速统计。
具体配置示例
http { # 定义映射规则:仅当后端返回200时,把客户端二进制IP赋值给$limited_ip,否则为空 map $status $limited_ip { default ""; 200 $binary_remote_addr; } # 基于$limited_ip创建限速区域,只有非空的$limited_ip才会被统计 limit_req_zone $limited_ip zone=success_only:10m rate=2r/m; server { location / { proxy_pass http://localhost:3000/; # 确保NGINX不拦截后端的错误状态码,让$status能拿到真实的返回码 proxy_intercept_errors off; # 仅当$limited_ip非空(即返回200)时,触发限速规则 limit_req zone=success_only nodelay; # 其他原有配置... } # 其他server配置... } # 其他http配置... }
关键配置解释
map $status $limited_ip:这个指令是核心,它会根据后端返回的$status值动态设置$limited_ip。默认情况下变量为空,只有当状态码是200时,才会把客户端的二进制IP($binary_remote_addr,比普通IP更节省内存)赋值给它。limit_req_zone $limited_ip ...:限速区域基于$limited_ip创建,空字符串不会被计入统计,所以只有成功请求才会占用这个区域的配额。proxy_intercept_errors off:默认情况下NGINX会拦截4xx/5xx的错误状态码并返回自己的错误页面,开启这个参数可以让$status准确获取后端返回的真实状态码,保证映射规则生效。nodelay参数:可选配置,如果不想让超出速率的成功请求排队等待,而是直接返回503错误,可以加上这个参数;如果允许短时间排队,可以去掉。
测试建议
- 故意提交错误的表单(比如缺少必填字段),连续提交多次,验证是否不会触发限速。
- 连续提交正确的表单,触发200返回,验证是否在每分钟2次后触发限速限制。
内容的提问来源于stack exchange,提问作者Zak
相关产品推荐
相关产品推荐

