You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Nginx作为Django反向代理时遭遇CORS问题求助

问题诊断与修复方案

核心问题分析

  1. Nginx CORS头重复冲突:同时用proxy_set_header和add_header设置CORS头,会导致响应头重复触发浏览器拦截;且默认add_header仅对200/301等成功状态码生效,错误响应不会携带CORS头。
  2. HTTPS识别缺失:前端通过Cloudflare走HTTPS,但Nginx内部监听80,未给Django传递X-Forwarded-Proto头,导致Django无法正确识别请求协议,影响CORS判断和CSRF验证。
  3. Django CORS配置遗漏:CORS_ALLOWED_ORIGINS里未明确添加生产环境的https://example.com(仅包含http版本和带端口的本地配置)。
  4. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 14:20:40