【踩坑记录】Django + Nginx + WebSocket + JWT 跨域问题全解析(含完整解决方案)

最近在做一个 Django + Vue的小项目时,遇到了一连串跨域(CORS)问题。尤其是:

  • 静态资源 /static/

  • 媒体文件 /media/

  • 自定义后端接口 /settings/*

  • WebSocket /wss

  • JWT 鉴权(Authorization 头)

  • 浏览器 OPTIONS 预检请求

这些问题混在一起,让整个调试过程非常痛苦。
这篇博客记录我遇到的问题、踩过的坑,和最终的完整解决方案,希望能帮到后面遇到同样问题的人。


1. 问题场景

前端部署在:某网站

后端 API 服务部署在:

https://kingpole.site

前端通过 AJAX 向后端发送请求时,被浏览器 CORS 拦截,报错如下:

Access to XMLHttpRequest at 'https://kingpole.site/settings/ranklist/' 
from origin '网站' has been blocked by CORS policy: 
Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

这是典型的:

  • 浏览器发起 OPTIONS 预检请求

  • 后端 Nginx 返回的 CORS Header 不完整

  • 导致浏览器认为跨域不安全 → 拦截


2. 问题根源:Authorization 请求头未被允许

浏览器发送的预检请求:

OPTIONS /settings/ranklist/
Access-Control-Request-Headers: authorization, content-type
Origin: https://www.acwing.com

但 Nginx 响应是这样的(不完整):

Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,Content-Type,Range

注意:
里面缺少 Authorization

所以浏览器拒绝跨域。


3. 我遇到的三个典型跨域问题

3.1 静态文件 /static 跨域问题

浏览器加载图片、CSS、JS 时,也会触发跨域。

解决方式:给 Nginx 的 /static 增加允许跨域头。


3.2 媒体文件 /media PUT / GET 跨域

上传头像 / 读取图片时浏览器会触发跨域,尤其是 PUT 方法,必须处理 OPTIONS 预检。


3.3 最棘手:需要使用 Authorization 的跨域请求

例如 Django JWT:

Authorization: Bearer xxxxx

浏览器默认会发 OPTIONS 请求,如果后端不允许此 header,直接报错。


4. 最终完整解决方案(亲测可用)

下面是我最终可用的 Nginx 配置片段(核心内容)。
这段配置是文章的核心,直接可用。


✔ Nginx API 接口跨域(最关键)

# 所有后端接口
location / {
    add_header Access-Control-Allow-Origin 网站;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, X-Amz-Date, Cache-Control, DNT, User-Agent, If-Modified-Since, Range" always;
    add_header Access-Control-Expose-Headers "Content-Length, Content-Range" always;

    if ($request_method = OPTIONS) {
        return 204;
    }

    proxy_pass http://127.0.0.1:8000;
}

✔ 静态文件 /static 跨域

location /static/ {
    alias /home/acs/djapp/static/;
    add_header Access-Control-Allow-Origin 网站;
}

✔ 媒体文件 /media 跨域(含 PUT 上传)

location /media {
    alias /home/acs/djapp/media/;

    if ($request_method = OPTIONS) {
        add_header 'Access-Control-Allow-Origin' '网站';
        add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
        add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Requested-With, X-Amz-Date, Cache-Control, DNT, User-Agent, If-Modified-Since, Range';
        return 204;
    }
}

✔ WebSocket /wss 跨域

注意:WebSocket 不走 OPTIONS,但需要 Upgrade header

location /wss {
    add_header Access-Control-Allow-Origin 网站;

    proxy_pass http://127.0.0.1:5015;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

5. 跨域的问题解决了,但我还遇到了 Token 401…

在跨域解决后,我遇到新的错误:

401 Unauthorized

原因是:

  • 浏览器刷新页面后旧 access token 已过期

  • 前端启动时直接用旧 access 调 /getinfo/

  • 被后端拒绝 → 401

这个问题通过前端逻辑修复:

启动时 → 先用 refresh token 换取新的 access token

换成功后再访问 getinfo、ranklist。

这是 JWT 项目的必备逻辑,不属于跨域问题,但要一起处理。


6. 跨域排查经验总结(干货)

跨域问题排查其实就 4 步:


✔ Step 1:看浏览器控制台

如果报错关键词出现如:

blocked by CORS policy
preflight response ...
Request header field ... is not allowed

说明 CORS 配置不完整。


✔ Step 2:看 OPTIONS 请求

浏览器自动发出的请求:

OPTIONS /api/ranklist/

你必须保证服务器返回:

  • 204 No Content

  • 带全部允许的 Header

  • 允许 Origin

  • 允许 Method

否则浏览器不会继续发送正式请求。


✔ Step 3:重点检查 Authorization

99% 的跨域失败都因为这个头没有放行:

Authorization

✔ Step 4:Nginx 的 CORS 要加 always

否则 301/304 等响应不会带 CORS Header。

正确写法:

add_header Access-Control-Allow-Origin 网站 always;

7. 结语

跨域问题本质上不是服务器“禁止”访问,而是浏览器主动拦截。
特别是:

  • 不同域名

  • 带 Authorization

  • 带自定义 Header

  • 非 GET/POST 的方法(PUT/DELETE)

  • WebSocket

这些情况都会触发 CORS 机制。

这篇博客把整个排查过程完整记录,附上亲测可用的配置,希望能减少大家踩坑时间。

如果你也遇到跨域 + JWT + WebSocket 的组合问题,可以按我这篇文章的配置逐行对照,一般都能解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值