nginx 应在鉴权和代理前直接拦截 options 请求并返回 204,避免其进入 auth_request 或后端鉴权流程;需在 location 中用 if 判断并设置带 always 的 cors 响应头,或通过独立 location @options 统一处理。

Nginx 层直接拦截 OPTIONS 请求,避免它被转发到后端触发 401,核心是 不让 OPTIONS 进入鉴权流程 —— 因为预检本身不需要认证,也不该被 auth_request 或后端鉴权逻辑处理。
✅ 明确前提:OPTIONS 请求不该走鉴权链
浏览器发起跨域请求前的 OPTIONS 预检,不携带业务数据,也不含有效 Token(即使带了,后端也不应校验)。若它被 proxy_pass 转发、又被 auth_request 拦截或后端返回 401,说明 Nginx 配置把预检和真实请求混同处理了。必须在鉴权/代理之前就“截停”它。
? 正确做法:在 location 中显式响应 OPTIONS,不转发、不鉴权
location /api/ {
# 先拦截 OPTIONS,立即返回 204
if ($request_method = "OPTIONS") {
add_header Access-Control-Allow-Origin "$http_origin" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With" always;
add_header Access-Control-Expose-Headers "X-Total-Count, X-Page-Count" always;
add_header Access-Control-Allow-Credentials "true" always;
add_header Access-Control-Max-Age "86400" always;
return 204;
}
# 后续请求才走鉴权和代理
auth_request /auth;
proxy_pass http://backend;
proxy_set_header Host $host;
}
⚠️ 注意:
-
if在 location 内使用是安全的(Nginx 官方允许用于return和add_header) - 所有 CORS 头必须用
always参数,否则在return 204时不会生效 - 不要让
auth_request或proxy_pass对 OPTIONS 生效 ——if提前终止,后续指令不执行
? 常见错误配置(导致 401)
- 把
auth_request放在 server 块或 http 块顶层,未按路径隔离,OPTIONS 也被强制鉴权 - location 中没匹配
OPTIONS,请求落入默认 proxy_pass,后端无 OPTIONS 接口 → 返回 405 或 401 - 用了
limit_except但未包含 OPTIONS,或配置了deny all导致预检被拒绝
✅ 进阶优化:分离预检与主请求逻辑
更清晰的做法是用独立 location 拦截所有 OPTIONS:
# 单独处理所有 OPTIONS 请求(推荐)
location @options {
add_header Access-Control-Allow-Origin "$http_origin" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With" always;
add_header Access-Control-Allow-Credentials "true" always;
add_header Access-Control-Max-Age "86400" always;
return 204;
}
location /api/ {
if ($request_method = "OPTIONS") {
rewrite ^(.*)$ @options last;
}
auth_request /auth;
proxy_pass http://backend;
}
这样逻辑更解耦,也方便统一管理 CORS 策略。
? 补充:确保 Origin 校验(可选增强)
如需限制来源,可用 map 提前判断:
map $http_origin $cors_origin {
default "";
"~^https?://(example\.com|app\.domain\.xyz)$" "$http_origin";
}
# 然后在 add_header 中写:
add_header Access-Control-Allow-Origin "$cors_origin" always;
若 $cors_origin 为空,该 header 不会发送,浏览器视为不允许多源访问。
Nginx 层拦截 OPTIONS 是标准实践,不是权宜之计。它既减轻后端压力,又避免因预检触发鉴权失败导致真实请求被阻断。关键就是:别让它进 pipeline,第一时间响应。











