Nginx中用if判断$request_method处理OPTIONS预检请求,可统一location内差异化响应、避免透传后端;需配合add_header与return 204使用,禁用proxy_pass等指令,注意Origin白名单与credentials兼容性。

在 Nginx 中处理跨域(CORS)请求时,对 OPTIONS 预检请求的正确响应是关键。虽然很多人直接用 add_header 配合 location 块处理,但若需根据请求方法动态控制行为(比如只对特定 HTTP 方法放行、或对 OPTIONS 单独返回 204),if 指令配合 $request_method 是实用且可控的方式——但要注意它的使用边界。
为什么用 if 判断 $request_method 处理 OPTIONS?
Nginx 的 if 在 location 块中可用于条件匹配请求方法,尤其适合:需要统一 location 配置但差异化响应;预检请求无需转发到后端;或需在同 location 内区分 GET/POST 和 OPTIONS 行为。注意:if 不能嵌套,且不支持在 server 级直接做响应体控制(如 return),必须配合 location 使用。
基础配置:拦截并快速响应 OPTIONS 请求
以下是在一个 API location 中的典型写法:
- 用
if ($request_method = 'OPTIONS') { ... }捕获预检请求 - 内部用
add_header设置 CORS 头(Nginx 1.13.12+ 支持在 if 块中安全使用) - 用
return 204立即结束请求,避免透传给后端 - 确保其他方法(如 GET/POST)继续走 proxy_pass 或 try_files 流程
示例片段:
location /api/ {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";
add_header Access-Control-Max-Age 1728000;
add_header Access-Control-Expose-Headers "Content-Length,Content-Range";
add_header Access-Control-Allow-Credentials "true";
return 204;
}
<pre class='brush:php;toolbar:false;'># 其他请求正常代理
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;}
进阶技巧:按来源或路径精细化控制
单纯用 if ($request_method = 'OPTIONS') 是安全的,但若叠加其他变量(如 $http_origin),需格外注意:
-
if ($http_origin ~* ^https?://(localhost|myapp\.com))可实现白名单 Origin 控制 - 避免在 if 中使用
proxy_pass、rewrite等可能引发重入的指令 - 若需携带凭证(
credentials: true),Access-Control-Allow-Origin不能为*,必须回显具体 origin,此时建议用 map 提前定义可信源再引用 - 多个 if 判断会顺序执行,但不支持 else,逻辑复杂时推荐用
map+add_header组合替代
常见坑与规避建议
实际部署中容易踩的点:
-
if块内不能使用proxy_pass—— 这会导致 400 或 500 错误,必须把代理逻辑放在 if 外 -
add_header在 if 中生效的前提是:该响应确实由当前 location 发出(即 return 204 成功触发);否则父块或 server 块的 header 可能覆盖 - 浏览器对预检缓存依赖
Access-Control-Max-Age,设太小会导致频繁 OPTIONS 请求,建议至少 86400(24 小时) - 调试时可用
curl -H "Origin: http://test.com" -X OPTIONS -I http://yourdomain/api/验证响应头是否完整

















