加always参数可解决405响应缺CORS头问题,但仅当405由Nginx自身返回时有效;若由后端返回或为内置错误页,则需拦截OPTIONS请求return 204或用error_page 405=200重写。
直接加
就能解决 405 响应里缺 CORS 头的问题,但前提是:这个 405 真的是 Nginx 自己返回的,而不是后端服务返回后被 Nginx 转发出去的。
为什么 405 响应默认没有 CORS 头
Nginx 的
指令默认只对成功响应(2xx、3xx)生效。遇到 405 这类错误响应时,Nginx 不会自动添加你配置的头——哪怕你在
块里写了
,它也不会出现在 405 响应里。
这会导致两个实际问题:
前端发 OPTIONS 预检请求,Nginx 因路径不匹配或方法不支持直接返回 405,但没带 CORS 头,浏览器直接报错“preflight response has invalid HTTP status code”
漏洞扫描工具检测到 405 响应缺少安全头(如
),标记为风险项
add_header … always 的作用和写法
参数让
强制作用于所有响应,包括 4xx 和 5xx。这是最直接有效的修复方式。
正确写法示例:
注意:
必须紧接在
后面,不能换行,也不能加引号包裹
。
但光加 always 可能还不够:先确认 405 是谁返回的
如果 405 是后端服务返回的(比如 Spring Boot 或 Node.js 接口不支持 OPTIONS),Nginx 默认只是透传响应,不会重写头。此时
依然无效——因为 Nginx 不会修改已存在的响应头,除非你显式开启透传控制。
Nginx
在宝塔面板中轻松管理Nginx高性能Web服务器。提供可视化配置反向代理、负载均衡、SSL证书及HTTP缓存功能,一键优化高并发性能,助您高效搭建稳定、快速的网站运行环境。
下载
应对方法有两种:
推荐:在
块中拦截 OPTIONS 请求,主动 return 204(或 200),并在 if 块内加全 CORS 头(含
)
次选:启用
并配合
,但有安全风险,一般不建议
拦截写法示例:
顺便解决 405 页面无法显示 CORS 头的连带问题
有些场景下,用户访问一个不存在的接口路径(如
),Nginx 因未配置对应
,回落到
块处理,而该块只允许 GET,导致返回 405。这时即使加了
,CORS 头也加不到错误页上——因为 405 响应由 Nginx 内置错误页机制生成,
对其无效。
稳妥做法是显式捕获并重写:
这句放在 server 或 http 块里,能让 405 被转成 200 后再走正常响应流程,
就能生效了。
alwaysadd_headerlocationadd_header Access-Control-Allow-Origin "*"Access-Control-Allow-Originalwaysadd_headerlocation /api/ {
proxy_pass http://backend;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Authorization' always;
}alwaysadd_headeralwaysadd_header ... alwayslocationalwaysproxy_pass_request_headers onadd_header ... alwayslocation /api/ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Authorization' always;
add_header 'Access-Control-Max-Age' 1728000 always;
add_header 'Content-Type' 'text/plain; charset=utf-8' always;
add_header 'Content-Length' 0 always;
return 204;
}
proxy_pass http://backend;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
}/v1/xxxlocation/alwaysadd_headererror_page 405 =200 $request_uri;add_header ... always