无法配置NGINX处理CORS跨域请求,请求排查问题原因
一、NGINX配置中的核心问题
缺失关键CORS响应头
你的HTTPS(443端口)server块里完全没加Access-Control-Allow-Origin头,这是CORS验证的核心响应头,必须添加。另外你重复写了两次Access-Control-Allow-Methods "*",属于冗余操作,删掉一个即可。配置语法错误
配置里有一行include /etc/l,明显是不完整的路径(应该是Certbot生成的include /etc/letsencrypt/options-ssl-nginx.conf;),语法错误会导致NGINX无法正确加载配置,所有自定义头的设置都不会生效。未处理OPTIONS预检请求
你的前端请求带了X-Requested-With自定义头,浏览器会先发送OPTIONS预检请求验证权限,但当前配置没有专门处理OPTIONS请求,需要添加对应的location块返回预检所需的头。HTTP(80端口)配置无效
80端口的server块里,add_header指令放在if块外面,但当if块触发301跳转时,这些头不会被携带;而且HTTP跳转的CORS头对HTTPS的API请求没有意义,无需在80端口配置CORS。
二、前端代码中的问题
前端请求里设置了xmlhttp.setRequestHeader('Access-Control-Allow-Origin', '*');,这是完全错误的——Access-Control-Allow-Origin是后端返回的响应头,不是前端发送的请求头,添加这个请求头不仅没用,还可能干扰预检逻辑,必须删掉。
修复后的NGINX配置
server { server_name api.example.com; index file.json; location / { root /var/www/example/html; default_type application/json; add_header Content-Type application/json; # 核心CORS头,允许前端域名跨域,建议指定具体域名而非*(如果需要带Cookie的话) add_header Access-Control-Allow-Origin "https://www.example.com"; add_header Access-Control-Allow-Methods "*"; # 允许自定义请求头,包含你前端用的X-Requested-With add_header Access-Control-Allow-Headers "X-Requested-With, Content-Type"; } # 专门处理OPTIONS预检请求 location / { if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin "https://www.example.com"; add_header Access-Control-Allow-Methods "*"; add_header Access-Control-Allow-Headers "X-Requested-With, Content-Type"; # 预检请求的缓存时间,减少重复OPTIONS请求 add_header Access-Control-Max-Age 3600; add_header Content-Length 0; add_header Content-Type text/plain; return 204; } } listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem; # managed by Certbot # 补全Certbot的include指令 include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { listen 80; server_name api.example.com; # 直接跳转到HTTPS,无需CORS头 return 301 https://$host$request_uri; }
修复后的前端代码
var xmlhttp = new XMLHttpRequest(); var url = "https://api.example.com"; xmlhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var myArr = JSON.parse(this.responseText); console.log(myArr); } }; xmlhttp.open("GET", url, true); xmlhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // 删掉错误的Access-Control-Allow-Origin请求头 xmlhttp.send();
额外说明
- 如果你不需要携带Cookie,
Access-Control-Allow-Origin可以用*,但建议指定具体的前端域名(https://www.example.com),更安全。 - 修改NGINX配置后,记得执行
sudo nginx -t验证配置语法,然后sudo systemctl reload nginx重启服务生效。
内容的提问来源于stack exchange,提问作者兄弟鏈

