1. 为什么需要Nginx跨域配置
当浏览器发起跨域请求时,会触发同源策略的安全检查。最近在调试前端项目时,我频繁遇到这样的报错:"has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource"。这正是典型的跨域问题,而Nginx作为最流行的Web服务器之一,其跨域配置是每个开发者都应该掌握的技能。
跨域问题本质上源于浏览器的安全限制。当你的前端应用运行在http://localhost:3000,而API服务部署在http://api.example.com时,浏览器会阻止这种跨域请求。这不是服务端不能响应,而是浏览器主动拦截了响应结果。通过Nginx配置CORS(跨域资源共享)规则,我们可以安全地解除这种限制。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. CORS核心头部字段解析
2.1 基础必备头部
nginx复制add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
Access-Control-Allow-Origin: 控制哪些源可以访问资源。生产环境建议替换*为具体的域名,如http://your-frontend.comAccess-Control-Allow-Methods: 声明允许的HTTP方法Access-Control-Allow-Headers: 声明允许的请求头字段
2.2 预检请求处理
对于非简单请求(如Content-Type为application/json),浏览器会先发送OPTIONS预检请求:
nginx复制location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin '*';
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers '*';
add_header Access-Control-Max-Age 1728000;
add_header Content-Type 'text/plain; charset=utf-8';
add_header Content-Length 0;
return 204;
}
}
Access-Control-Max-Age指定预检请求结果的缓存时间(秒),减少不必要的OPTIONS请求。
3. 生产环境推荐配置方案
3.1 多域名白名单配置
nginx复制map $http_origin $cors_origin {
default "";
"~^https://(www\.)?example1.com$" "$http_origin";
"~^https://(www\.)?example2.com$" "$http_origin";
}
server {
location / {
if ($cors_origin) {
add_header 'Access-Control-Allow-Origin' $cors_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
}
}
}
这种方案使用map指令实现动态域名匹配,比硬编码更灵活安全。注意当设置Access-Control-Allow-Credentials: true时,Access-Control-Allow-Origin不能为*。
3.2 带Cookie的跨域请求
当需要传递Cookie等凭证信息时:
nginx复制add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
客户端需要相应设置:
javascript复制fetch(url, {
credentials: 'include'
})
4. 常见问题排查指南
4.1 配置不生效检查清单
- 检查配置加载:执行
nginx -t测试配置,nginx -s reload重载配置 - 验证响应头:使用curl命令检查响应头
bash复制
curl -I -X OPTIONS http://your-domain.com/api - 缓存问题:浏览器可能会缓存CORS响应头,尝试无痕模式访问
- 正则匹配:确保map指令中的正则表达式正确匹配你的域名
4.2 特殊场景处理
案例1:Nginx作为反向代理时的配置
nginx复制location /api/ {
proxy_pass http://backend-server;
proxy_set_header Host $host;
# CORS配置
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin '*';
add_header Access-Control-Allow-Methods '*';
add_header Access-Control-Allow-Headers '*';
add_header Content-Length 0;
return 204;
}
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Methods '*' always;
add_header Access-Control-Allow-Headers '*' always;
}
案例2:WebSocket跨域配置
nginx复制location /socket.io/ {
proxy_pass http://websocket-server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# CORS配置
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'Authorization, Content-Type';
}
5. 安全加固建议
- 避免过度开放:生产环境不要使用
Access-Control-Allow-Origin: * - 限制HTTP方法:根据实际需要开放方法,不要使用
* - 设置Vary头:当根据Origin动态返回时,添加
Vary: Origin防止缓存污染nginx复制add_header Vary Origin; - 结合速率限制:防止CORS接口被滥用
nginx复制limit_req_zone $binary_remote_addr zone=cors_api:10m rate=10r/s; location /api/ { limit_req zone=cors_api burst=20; # ...其他配置 }
6. 调试技巧与工具
-
浏览器开发者工具:
- 查看Network标签中的请求/响应头
- 注意是否有CORS相关的警告或错误
-
Postman测试:
- 添加
Origin请求头模拟跨域场景 - 测试OPTIONS预检请求
- 添加
-
Nginx日志分析:
nginx复制log_format cors_debug '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_origin" "$http_user_agent"'; server { access_log /var/log/nginx/cors.log cors_debug; }
在实际项目中,我建议将CORS配置封装成独立的配置文件(如cors.conf),通过include指令复用:
nginx复制# /etc/nginx/conf.d/cors.conf
map $http_origin $cors_origin {
# 域名配置
}
# 主配置文件中
server {
include conf.d/cors.conf;
location / {
if ($cors_origin) {
add_header Access-Control-Allow-Origin $cors_origin;
# 其他头部...
}
}
}
这种模块化配置方式便于维护,特别是在微服务架构下,可以确保所有服务的CORS策略保持一致。
