Nginx 无法通过 limit_req_status 返回自定义 JSON,需结合 error_page 429 与 return 或 alias 实现:先用 limit_req_status 设 429 状态码,再用 error_page 捕获并返回 JSON 响应体。

Nginx 本身不支持直接通过 limit_req_status 配置返回自定义 JSON 内容,该指令仅用于设置限流触发时的 HTTP 状态码(如 429),不能控制响应体。要返回结构化 JSON 错误(如 {"code":429,"msg":"Too many requests"}),需结合 error_page + return 或 add_header + 自定义错误页实现。
使用 error_page 拦截 429 并 return JSON
这是最简洁可靠的方式:先用 limit_req_status 429 触发标准限流状态码,再用 error_page 429 捕获并覆盖响应体为 JSON。
- 在
http、server或location块中配置限流及错误重定向:
limit_req_zone $binary_remote_addr zone=api:10m rate=5r/s;
<p>server {
listen 80;
server_name example.com;</p><pre class="brush:php;toolbar:false;">location /api/ {
limit_req zone=api burst=10 nodelay;
limit_req_status 429; # 显式设为 429(可选,默认即 429)
# 拦截 429 并返回 JSON
error_page 429 = @rate_limit_exceeded;
}
location @rate_limit_exceeded {
internal;
add_header Content-Type "application/json; charset=utf-8";
return 429 '{"code":429,"msg":"Too many requests","retry_after":60}';
}
}
-
internal确保该 location 只能被内部跳转访问,防止直接请求 -
return的第一个参数是状态码,第二个是完整响应体(支持内联 JSON 字符串) - 注意 JSON 中的双引号需用反斜杠转义(Nginx 配置中),或改用单引号包裹整个字符串(如上例)
配合自定义错误页面(适合复杂 JSON 或多语言)
若 JSON 内容较长、含变量或需服务端渲染,可将 JSON 写入静态文件,再由 error_page 指向:
- 创建
/usr/share/nginx/html/429.json:
{"code":429,"msg":"请求过于频繁,请稍后再试","timestamp":1717023456}- 在 Nginx 配置中引用:
error_page 429 /429.json;
location = /429.json {
internal;
add_header Content-Type "application/json; charset=utf-8";
alias /usr/share/nginx/html/429.json;
}-
alias比root更适合精确映射单个文件 - 仍需
add_header显式设置Content-Type,否则可能返回text/plain
避免常见陷阱
-
limit_req_status不影响响应体 —— 它只改状态码;真正替换内容靠error_page + return或alias - 不要在非
internallocation 中用return处理 429,否则可能造成重定向循环或暴露内部路径 - 确保 JSON 字符串语法正确:Nginx 不校验 JSON 格式,错误会导致响应体乱码或空内容
- 若使用
proxy_pass后端,限流应在 Nginx 层完成,而非依赖后端返回 429(否则无法用error_page拦截)
验证是否生效
用 curl 快速测试:
curl -I https://www.php.cn/link/098a1f7a79573bbd9ae59aff7b576622 # 应看到: # HTTP/1.1 429 Too Many Requests # Content-Type: application/json; charset=utf-8 <p>curl <a href="https://www.php.cn/link/098a1f7a79573bbd9ae59aff7b576622">https://www.php.cn/link/098a1f7a79573bbd9ae59aff7b576622</a></p><h1>应看到完整 JSON 响应体</h1>
- 检查响应头中
Content-Type是否正确 - 确认状态码为
429且响应体是预期 JSON,而非默认 Nginx 429 页面











