使用Nginx作为Django反向代理时遭遇CORS问题求助
问题诊断与修复方案
核心问题分析
- Nginx CORS头重复冲突:同时用
proxy_set_header和add_header设置CORS头,会导致响应头重复触发浏览器拦截;且默认add_header仅对200/301等成功状态码生效,错误响应不会携带CORS头。 - HTTPS识别缺失:前端通过Cloudflare走HTTPS,但Nginx内部监听80,未给Django传递
X-Forwarded-Proto头,导致Django无法正确识别请求协议,影响CORS判断和CSRF验证。 - Django CORS配置遗漏:
CORS_ALLOWED_ORIGINS里未明确添加生产环境的https://example.com(仅包含http版本和带端口的本地配置)。 - OPTIONS请求处理不规范:用
if指令处理OPTIONS请求容易触发Nginx上下文逻辑问题,导致预检请求处理异常。
修复步骤
1. 修正Nginx API服务器配置
删除冗余的CORS代理头,单独处理OPTIONS预检请求,同时添加HTTPS转发标识:
upstream djangoserver { server django:8000; } server { listen 80; listen [::]:80; server_name $API_DOMAIN_HOSTNAME; # 单独处理OPTIONS预检请求 if ($request_method = OPTIONS) { add_header 'Access-Control-Allow-Origin' 'https://example.com'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-CSRFToken'; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Content-Length' '0'; return 204; } location / { proxy_pass http://djangoserver; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; # 告知Django当前请求为HTTPS(Cloudflare转成80端口给Nginx) proxy_set_header X-Forwarded-Proto $scheme; # 用always参数确保所有响应都携带CORS头 add_header 'Access-Control-Allow-Origin' 'https://example.com' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-CSRFToken' always; } }
2. 修正Django配置
- 补充生产环境HTTPS域名到CORS允许列表:
CORS_ALLOWED_ORIGINS = [ # 保留原有本地调试配置... "https://" + os.environ.get('FRONTEND_DOMAIN_HOSTNAME'), # 添加这行,对应https://example.com ]
- 配置Django信任反向代理,添加到
settings.py:
# 信任Nginx传递的HTTPS标识 SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') USE_X_FORWARDED_HOST = True USE_X_FORWARDED_PORT = True
- 确保API域名被允许:
ALLOWED_HOSTS = [ # 保留原有配置... os.environ.get('API_DOMAIN_HOSTNAME'), # 添加api.example.com ]
3. 额外检查项
- 确认Cloudflare SSL模式设为Full或Full (strict),避免HTTP/HTTPS混合请求问题。
- 清除浏览器缓存后再测试,CORS头会被浏览器缓存,旧的错误配置可能残留。
- 检查Axios配置:不要手动设置
Origin头,让浏览器自动处理;带凭证的请求禁止用通配符*作为允许源(当前配置已符合要求)。
方案合理性说明
你采用的主域名部署前端、子域名部署API的方案是前后端分离的标准实践,本身没有问题,故障源于配置细节的遗漏和Nginx指令的误用,修正后即可解决CORS问题。
内容的提问来源于stack exchange,提问作者user20984154
相关产品推荐
相关产品推荐

