跨域失败主因是预检请求options未被nginx处理,导致add_header不生效;须显式配置options响应、重载nginx、避免credentials与*共存、确保协议一致,并通过devtools定位真实拦截点。

为什么加了 add_header Access-Control-Allow-Origin 还是跨域失败
因为浏览器的预检请求(OPTIONS)根本没走到你的业务 location 块里,Nginx 默认不处理 OPTIONS,直接 405 或 404。你写的 add_header 只对 2xx/3xx 响应生效,而预检失败时压根没进后端,header 根本不会发出去。
实操建议:
- 必须在 server 或 location 块里显式处理
OPTIONS请求,返回 204 状态码 -
add_header要放在能覆盖所有响应路径的位置(比如 server 级),不能只写在 proxy_pass 的 location 里 - 如果用了
if ($request_method = 'OPTIONS') { ... },注意 Nginx 中if在 location 里有作用域限制,优先用try_files+ 空文件或直接return 204
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 "Content-Type, Authorization";
add_header Access-Control-Allow-Credentials "true";
return 204;
}
proxy_pass http://backend;
}
宝塔面板里改 Nginx 配置后不生效的常见原因
不是点了“保存”就完事——宝塔会校验语法,但不会自动重载;而且它可能把你的修改写进了子配置文件,却被主配置里的 include 顺序或重复块覆盖。
实操建议:
- 改完点“保存”后,**必须手动点“重载配置”**(不是重启 Nginx),否则配置仍在内存里没加载
- 检查是否误改了默认站点配置,而实际域名绑定了另一个站点——宝塔为每个站点生成独立 conf,要进对应站点的“配置文件”里改
- 避免在“网站目录”或“反向代理”页面里点“添加”,那会自动生成带冲突规则的 block,和你手写的
add_header冲突 - 用命令行验证:
nginx -t看语法,nginx -T | grep -A5 'Access-Control'看最终生效位置
Access-Control-Allow-Credentials: true 和 * 不能共存
这是浏览器强制要求:一旦前端设置了 credentials: 'include',后端就不能用通配符 * 做 Access-Control-Allow-Origin,否则浏览器直接拒绝响应。
实操建议:
- 要么前端去掉 credentials(适合纯公开接口)
- 要么后端动态读取请求头中的
Origin,只回写这个值(注意校验白名单,防 XSS) - 宝塔里没法直接写动态逻辑,得用
map指令做映射,例如在 http 块里定义:map $http_origin $cors_origin { ~^https?://(localhost|myapp\.com):?[0-9]*$ $http_origin; default ""; }然后在 location 里用add_header Access-Control-Allow-Origin $cors_origin
HTTPS 站点下跨域请求被拦截的隐藏条件
不只是 header 缺失的问题。当你的前端是 https://a.com,后端 API 是 http://b.com(即混用 HTTP),现代浏览器会直接阻止,连 OPTIONS 都不发——这是混合内容(Mixed Content)策略,比 CORS 更早触发。
实操建议:
- 确保 API 地址协议与前端一致,尤其是宝塔反向代理时,
proxy_pass必须写https://(且后端证书有效)或走内网 HTTP(如http://127.0.0.1:3000) - 检查浏览器控制台 Network 标签页,看请求是否显示 “Blocked:mixed-content”,而不是 “CORS error”
- 不要依赖本地
localhost测试 HTTPS 站点的跨域,Chrome 对localhost有特殊策略,行为和真实域名不一致











