Nginx处理API跨域需区分简单请求与复杂请求:简单请求直接添加CORS响应头;复杂请求须显式拦截OPTIONS预检并返回204,同时动态匹配Origin提升安全性与灵活性。

要让 Nginx 正确处理 API 跨域请求,关键不是“一刀切”加 CORS 头,而是区分简单请求(Simple Request)和复杂请求(Preflighted Request),并针对性配置。Nginx 本身不主动发起预检(preflight),但必须正确响应浏览器发出的 OPTIONS 请求,并为实际请求附加合法的 CORS 响应头。
识别简单请求与复杂请求
浏览器自动判定:
-
简单请求:满足全部三个条件——方法是
GET、HEAD或POST;HTTP 头仅限Accept、Accept-Language、Content-Language、Content-Type(且值为application/x-www-form-urlencoded、multipart/form-data或text/plain);无自定义头。 -
复杂请求:不满足上述任一条件,例如使用
PUT/DELETE、Content-Type: application/json、带Authorization或X-Request-ID等自定义头——此时浏览器会先发一个OPTIONS预检请求,等待服务端明确允许后才发真实请求。
针对简单请求:直接添加 CORS 响应头
对非 OPTIONS 的正常请求(如 GET /api/users),只需在 location 块中设置标准 CORS 头:
location /api/ {
proxy_pass https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e;
proxy_set_header Host $host;
<pre class="brush:php;toolbar:false;">add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com';
add_header 'Access-Control-Allow-Credentials' 'true';
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-Expose-Headers' 'Content-Length,Content-Range';}
注意:Access-Control-Allow-Origin 不能设为 * 同时启用 credentials;若前端带 cookie 或 auth header,必须指定明确源(或动态判断后设置)。
针对复杂请求:显式处理 OPTIONS 预检
Nginx 默认不拦截或响应 OPTIONS 请求,需显式捕获并返回 204(无内容)成功响应:
location /api/ {
proxy_pass https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e;
proxy_set_header Host $host;
<pre class="brush:php;toolbar:false;"># 处理预检请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com';
add_header 'Access-Control-Allow-Credentials' 'true';
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 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
# 正常请求继续走 proxy_pass
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com';
add_header 'Access-Control-Allow-Credentials' 'true';
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-Expose-Headers' 'Content-Length,Content-Range';}
⚠️ 注意:if 在 location 中可用,但避免嵌套多层逻辑;生产环境建议用 map 提前定义变量提升性能,或用 try_files + 内部 location 分离预检逻辑。
进阶建议:安全与灵活性兼顾
不要硬编码 Origin——若需支持多个前端域名,可借助 map 模块动态匹配:
map $http_origin $cors_origin {
default "";
"~^https?://(localhost:3000|your-frontend\.com|staging\.app\.io)$" $http_origin;
}
<p>server {
location /api/ {
proxy_pass <a href="https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e">https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e</a>;</p><pre class="brush:php;toolbar:false;"> if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $cors_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
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 'Content-Length' 0;
return 204;
}
add_header 'Access-Control-Allow-Origin' $cors_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
# 其他头...
}}
同时确保后端不重复设置 CORS 头(避免冲突),Nginx 应作为统一网关层处理跨域。

















