最近在做一个 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 的组合问题,可以按我这篇文章的配置逐行对照,一般都能解决。
&spm=1001.2101.3001.5002&articleId=155017462&d=1&t=3&u=3531b794c36d4b03be6f70c49a22e774)
678

被折叠的 条评论
为什么被折叠?



