Become a sponsor

CORS跨域
CORS(Cross-Origin Resource Sharing)跨域资源共享是前后端分离架构必须处理的问题。项目使用 django-cors-headers 中间件处理跨域请求,通过 .env 配置允许的跨域源。
浏览器的同源策略限制了不同源(协议+域名+端口)之间的请求。前后端分离架构中,前端(如 http://localhost:8001)请求后端(如 http://127.0.0.1:8000)会产生跨域问题。
同源请求:http://localhost:8000/api/user → http://localhost:8000/api/role ✅
跨域请求:http://localhost:8001/api/user → http://localhost:8000/api/role ❌(端口不同)对于非简单请求(如 PUT/DELETE 或自定义 Header),浏览器会先发送 OPTIONS 预检请求:
浏览器 → OPTIONS /api/user → 服务器
浏览器 ← Access-Control-Allow-Origin: * ← 服务器
浏览器 → PUT /api/user → 服务器(正式请求)预检请求
django-cors-headers 中间件自动处理 OPTIONS 预检请求,无需手动编写代码。预检请求不会到达视图层,由中间件直接返回。
在 settings.py 中配置 CORS 相关参数:
# application/settings.py
INSTALLED_APPS = [
...
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # 必须在最前面
'django.middleware.common.CommonMiddleware',
...
]
# CORS 配置
CORS_ALLOW_ALL_ORIGINS = True # 开发环境允许所有源
CORS_ALLOW_CREDENTIALS = True # 允许携带凭证(Cookie/Authorization)
CORS_ALLOW_METHODS = [ # 允许的请求方法
'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT',
]
CORS_ALLOW_HEADERS = [ # 允许的请求头
'accept-encoding',
'authorization', # JWT 认证头
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'XMLHttpRequest',
'X_FILENAME',
'Pragma',
]# .env
# 开发环境:允许所有源
CORS_ALLOW_ALL_ORIGINS=True
# 生产环境:指定域名
# CORS_ALLOW_ALL_ORIGINS=False
# CORS_ALLOWED_ORIGINS=https://admin.example.com,https://www.example.com生产环境
生产环境务必设置 CORS_ALLOW_ALL_ORIGINS=False 并配置 CORS_ALLOWED_ORIGINS 为具体域名,避免允许所有源带来的安全风险。
# 生产环境:指定多个允许的域名
CORS_ALLOWED_ORIGINS = [
"https://admin.example.com",
"https://www.example.com",
"https://m.example.com",
]# 允许所有子域名
CORS_ALLOWED_ORIGIN_REGEXES = [
r"^https://.*\.example\.com$",
]如果不需要携带 Cookie,可以关闭凭证以提高安全性:
CORS_ALLOW_CREDENTIALS = False # 不允许携带凭证CORS 中间件必须在 MIDDLEWARE 列表中最前面注册:
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # ← 必须在最前面
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
]顺序重要
CorsMiddleware 必须在所有中间件之前,特别是要在 CommonMiddleware 之前。否则 OPTIONS 预检请求可能被 CommonMiddleware 拦截,导致 CORS 头未正确添加。
开发环境通过 Vite 代理解决跨域问题(无需 CORS):
// ui/vite.config.ts
server: {
proxy: {
'/api': {
target: 'http://127.0.0.1:8000',
changeOrigin: true,
}
}
}开发环境 vs 生产环境
/api 请求转发到后端,浏览器视为同源请求,不触发 CORS现象:浏览器控制台报 Access-Control-Allow-Origin 错误
排查:
# 1. 检查 CORS 中间件是否在最前面
grep -n "CorsMiddleware" application/settings.py
# 2. 检查 CORS 配置
grep -n "CORS_ALLOW" application/settings.py
# 3. 检查 .env 中的配置
cat .env | grep CORS现象:OPTIONS 请求被权限中间件拦截
排查:
# 检查 check_login 是否排除了 OPTIONS 请求
# middleware/login_middleware.py 中应放行 OPTIONS现象:自定义 Header(如 X-Token)被拒绝
解决:
# 在 CORS_ALLOW_HEADERS 中添加自定义 Header
CORS_ALLOW_HEADERS = [
...
'x-token',
'custom-header',
]现象:跨域请求中 Cookie 未携带
解决:
# 1. 后端设置
CORS_ALLOW_CREDENTIALS = True
# 2. 前端设置(Axios)
axios.defaults.withCredentials = true
# 3. 注意:Allow-Credentials 为 true 时,Allow-Origin 不能为 *1. 生产环境禁止 CORS_ALLOW_ALL_ORIGINS = True
2. 只允许必要的域名和请求方法
3. 谨慎使用 CORS_ALLOW_CREDENTIALS = True
4. 定期审查 CORS 配置,移除不再使用的域名
5. 避免在 CORS_ALLOW_HEADERS 中使用通配符 *CORS 跨域配置具备以下特点:
1. django-cors-headers:成熟的 Django CORS 解决方案
2. 环境变量配置:通过 .env 灵活配置允许的源
3. 开发/生产分离:开发环境允许所有源,生产环境指定域名
4. 中间件顺序:必须在 CommonMiddleware 之前
5. 前端代理:开发环境通过 Vite 代理解决跨域
6. 预检处理:自动处理 OPTIONS 预检请求
7. 安全可控:支持域名白名单、正则匹配、凭证控制