Nginx 配置跨域
在 Nginx 中配置跨域(CORS)是为了解决浏览器基于安全策略阻止跨域请求的问题。以下是针对 Nginx 跨域配置的分步详解,结合实际场景和代码示例:
一、跨域的核心机制与原因
什么是跨域?
- 浏览器基于同源策略(Same-Origin Policy),禁止页面从不同域名、端口或协议的服务器请求资源。
- 跨域触发条件:协议、域名、端口任意一个不同(例如
http://a.com
访问http://b.com
)。
如何解决跨域?
- 后端服务(如 Nginx)返回允许跨域的响应头(CORS Headers),告知浏览器允许哪些源访问资源。
二、Nginx 跨域配置全流程
在 Nginx 中配置跨域,主要通过添加 add_header
指令设置响应头。
1. 基础跨域配置(允许所有来源)
以下配置允许所有来源的跨域请求:
server {
listen 80;
server_name example.com;
location /api/ {
# 允许所有来源
add_header 'Access-Control-Allow-Origin' '*';
# 允许的请求方法(GET, POST等)
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
# 允许的请求头(如Content-Type、Authorization等)
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
# 允许浏览器暴露的响应头(供前端访问)
add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range';
# 预检请求(OPTIONS)缓存时间(单位:秒)
add_header 'Access-Control-Max-Age' 1728000;
# 反向代理到后端服务(如Java微服务)
proxy_pass http://backend-server;
}
}
2. 允许特定域名访问
如果只允许特定域名跨域(更安全):
add_header 'Access-Control-Allow-Origin' 'https://your-frontend-domain.com';
3. 处理预检请求(OPTIONS)
浏览器在发送复杂请求(如 PUT
、自定义头)前会先发送 OPTIONS
预检请求,需单独处理:
location /api/ {
# ...
# 处理 OPTIONS 请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://your-frontend-domain.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
add_header 'Access-Control-Max-Age' 1728000;
# 无需返回任何内容,浏览器只需要头部信息
return 204;
}
}
4. 支持携带凭证(Cookies、Credentials)
如果前端需要发送 Cookies 或认证信息,需额外配置 Access-Control-Allow-Credentials
,并禁止使用通配符 *
源:
add_header 'Access-Control-Allow-Origin' 'https://your-frontend-domain.com';
add_header 'Access-Control-Allow-Credentials' 'true';
三、配置关键点与注意事项
安全性问题:
- 生产环境中避免使用
Access-Control-Allow-Origin: *
,明确指定允许的域名。 - 对于动态允许多个域名,可通过 Nginx 变量结合
map
模块实现:
map $http_origin $cors_origin { default ""; ~^https?://(.*\.)?allowed-domain1.com$ $http_origin; ~^https?://(.*\.)?allowed-domain2.com$ $http_origin; } add_header 'Access-Control-Allow-Origin' $cors_origin;
- 生产环境中避免使用
缓存优化:
- 预检请求 (
OPTIONS
) 可通过Access-Control-Max-Age
减少频繁请求,节省带宽。
- 预检请求 (
常见错误排查:
- 头部顺序问题:确保在返回非
200
状态码(如204
)时仍能添加头部。 - 配置覆盖问题:若 Nginx 的父级块(如
http
)已定义add_header
,子级块的配置会覆盖父级。使用always
关键字强制添加头部:
add_header 'Access-Control-Allow-Origin' 'https://example.com' always;
- 头部顺序问题:确保在返回非
日志调试:查看
access.log
和error.log
检查配置是否生效:tail -f /var/log/nginx/access.log
四、实际场景案例
场景 1:前后端分离项目接口代理
前端运行在 http://localhost:3000
,通过 Nginx 代理后端 http://localhost:8080
的 API:
server {
listen 80;
server_name api.example.com;
location / {
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type' always;
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://localhost:8080;
}
}
场景 2:动态允许多个域名
白名单域名:example.com
和 test.com
:
map $http_origin $allowed_origin {
default "";
~^https?://(.*\.)?(example\.com|test\.com)$ $http_origin;
}
server {
location /api/ {
add_header 'Access-Control-Allow-Origin' $allowed_origin always;
# ...其他配置
}
}
五、参考资料
Nginx 官方文档
MDN Web(权威的 CORS 机制解释)
GitHub Gist 常见配置模板
Stack Overflow 调试技巧