一、跨域问题本质
浏览器基于 同源策略 (Same-Origin Policy) 限制以下行为:
- 触发条件:协议、域名、端口任一不同
- 限制类型:AJAX 请求、 Web 字体、 Web Workers 等
- 异常提示:No 'Access-Control-Allow-Origin' header is present
二、 Nginx 核心解决方案
方案 1:CORS 响应头配置
原理:通过设置 HTTP 响应头告知浏览器允许跨域
server {
location / {
<em># 基础跨域配置</em>
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Authorization' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
<em># 预检请求缓存</em>
add_header 'Access-Control-Max-Age' 1728000 always;
<em># 处理 OPTIONS 预检请求</em>
if ($request_method = 'OPTIONS') {
return 204;
}
}
}
方案 2:反向代理
原理:将跨域请求转换为同源请求
server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://backend-server:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
<em># 可选:添加CORS头双重保障</em>
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com';
}
}
三、高级配置技巧
1. 动态允许来源
map $http_origin $cors_header {
default "";
~^https?://(.*\.)?yourdomain.com(:\d+)?$ $http_origin;
~^https?://localhost(:\d+)?$ $http_origin;
}
server {
add_header 'Access-Control-Allow-Origin' $cors_header always;
}
2. 带凭证的请求
add_header 'Access-Control-Allow-Credentials' 'true' always;
<em># 必须指定具体域名,不能使用 *</em>
add_header 'Access-Control-Allow-Origin' 'https://your-frontend.com' always;
3. WebSocket 跨域
location /websocket/ {
proxy_pass http://backend_ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
<em># CORS for WebSocket</em>
if ($http_origin ~* (https?://.*\.yourdomain.com$)) {
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
}
}
四、最佳实践建议
- 安全策略
- 生产环境避免使用
*通配符使用 HTTPS 强制加密传输
add_header 'Access-Control-Allow-Origin' 'https://trusted-domain.com'; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - 生产环境避免使用
- 性能优化
- 合理设置
Access-Control-Max-Age减少预检请求合并静态资源请求
location ~* \.(woff2?|ttf|eot|svg|png|jpg)$ { add_header 'Access-Control-Allow-Origin' 'https://cdn.yourdomain.com'; expires 365d; } - 合理设置
- 调试技巧
- 使用 curl 验证响应头
curl -I -X OPTIONS https://api.yourdomain.com/resource- Chrome DevTools 网络标签检查 Headers
五、常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 配置生效但浏览器仍报错 | 缓存未更新 | 强制刷新 (Ctrl+F5) 或禁用缓存调试 |
| OPTIONS 请求返回 404 | Nginx 未正确处理 OPTIONS 方法 | 添加 if ($request_method = 'OPTIONS') 处理块 |
| 部分请求头未通过 | 未在 Access-Control-Allow-Headers 列出 | 添加缺失的请求头如 Authorization |
| 带 Cookie 请求失败 | 未设置 Allow-Credentials | 配置 add_header 'Access-Control-Allow-Credentials' 'true' |
通过以上配置策略,可构建安全高效的跨域解决方案。建议根据实际业务需求选择组合方案,并通过压力测试验证配置效果。