在前后端分离项目中,你是否遇到过这样的报错:“Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/' from origin 'http://localhost:8080' has been blocked by CORS policy”?这就是跨域资源共享(CORS) 限制导致的 —— 浏览器为了安全,会拦截不同域名 / 端口的请求

本文将详细讲解 Django 中配置 CORS 的 3 种方法,从推荐的第三方库到手动配置,再到个别视图的单独处理,最后附上 Vue 前端配合示例,帮你彻底解决跨域问题

一、什么是 CORS?为什么需要配置?

简单来说,CORS 是浏览器的一种安全机制:当前端(如 Vue 跑在 localhost:8080)向后端(Django 跑在 127.0.0.1:8000)发送请求时,由于域名 / 端口不同,浏览器会先发送一个 “预检请求(OPTIONS)”,确认后端允许跨域后才会发送真实请求

如果 Django 没有配置 CORS 规则,就会拒绝这个预检请求,导致前端请求失败

二、方法一:使用 django-cors-headers(推荐)

这是 Django 社区最常用、最稳定的跨域解决方案,支持丰富的配置项,兼顾开发效率和生产安全

步骤 1:安装依赖包

打开终端,执行 pip 安装命令:

pip install django-cors-headers

步骤 2:修改 settings.py 配置

这一步是核心,需要配置 “注册应用”“添加中间件” 和 “CORS 规则” 三部分,注意中间件顺序很重要

2.1 注册应用到 INSTALLED_APPS

在 settings.py 的 INSTALLED_APPS 列表中添加 corsheaders

# settings.py
INSTALLED_APPS = [
    # ... 其他已有的应用(如 django.contrib.admin、django.contrib.auth 等)
    'corsheaders',  # 新增:注册 cors 应用
    # ... 其他应用
]

2.2 添加中间件到 MIDDLEWARE

将 CorsMiddleware 放到 尽可能靠前的位置(建议在 SecurityMiddleware 之前),因为中间件是按顺序执行的,CORS 处理需要优先于其他请求处理:

# settings.py
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',  # 新增:CORS 中间件(放最前面)
    'django.middleware.security.SecurityMiddleware',  # Django 自带安全中间件
    'django.contrib.sessions.middleware.SessionMiddleware',  # 会话中间件
    # ... 其他中间件(如 CommonMiddleware、CsrfViewMiddleware 等)
]

2.3 配置 CORS 核心规则

根据环境(开发 / 生产)配置不同的规则,关键配置项如下:

# settings.py
# -------------------------- 1. 允许的域名(核心)--------------------------
# 开发环境:允许所有域名(方便调试,生产环境绝对不能用!)
CORS_ALLOW_ALL_ORIGINS = True  # 开发用,生产注释掉

# 生产环境:明确指定允许的域名(推荐,仅开放需要的域名)
# CORS_ALLOWED_ORIGINS = [
#     "https://yourdomain.com",  # 你的正式域名
#     "https://www.yourdomain.com",  # 带 www 的子域名
#     "http://localhost:8080",  # 若生产环境有前端调试需求,可临时加
# ]

# 进阶:允许符合正则的子域名(如 blog.yourdomain.com、admin.yourdomain.com)
# CORS_ALLOWED_ORIGIN_REGEXES = [
#     r"^https://\w+\.yourdomain\.com$",  # \w+ 匹配任意字母/数字/下划线
# ]

# -------------------------- 2. 允许的 HTTP 方法 --------------------------
# 默认已包含 GET/POST/PUT/DELETE 等,可按需扩展(一般不用改)
CORS_ALLOW_METHODS = [
    "DELETE",
    "GET",
    "OPTIONS",
    "PATCH",
    "POST",
    "PUT",
]

# -------------------------- 3. 允许的请求头 --------------------------
# 若前端需要传自定义头(如 Token、X-CSRFToken),需在这里添加
CORS_ALLOW_HEADERS = [
    "accept",
    "authorization",  # 用于 JWT Token 等认证
    "content-type",  # 用于 POST/PUT 的 JSON 数据
    "user-agent",
    "x-csrftoken",  # Django CSRF 防护需要
    "x-requested-with",
]

# -------------------------- 4. 允许携带凭证(如 Cookies、Token)--------------------------
# 若前端需要传 Cookies 或带认证信息,必须设为 True
CORS_ALLOW_CREDENTIALS = True

# -------------------------- 5. 预检请求缓存时间 --------------------------
# 浏览器发送预检请求后,会缓存结果,避免每次请求都发预检(单位:秒)
CORS_PREFLIGHT_MAX_AGE = 86400  # 1 天(默认 86400,可按需调整)

三、方法二:手动配置自定义中间件

如果不想依赖第三方库,可以自己写一个中间件来添加 CORS 响应头。这种方法灵活性高,但需要手动处理所有规则,适合简单场景

步骤 1:创建中间件文件

在你的 Django 应用(如 myapp)下新建 middleware.py 文件:

# myapp/middleware.py
class CorsMiddleware:
    def __init__(self, get_response):
        # 初始化:接收 Django 的 get_response 函数(必须)
        self.get_response = get_response

    def __call__(self, request):
        # 1. 先处理请求,得到响应对象
        response = self.get_response(request)

        # 2. 手动添加 CORS 响应头
        # 允许的域名:生产环境替换为具体域名(如 "https://yourdomain.com"),不要用 * 带凭证
        response["Access-Control-Allow-Origin"] = "*"
        # 允许的 HTTP 方法
        response["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
        # 允许的请求头(若前端传自定义头,需在这里添加)
        response["Access-Control-Allow-Headers"] = "Content-Type, Authorization, X-CSRFToken"
        # 允许携带凭证(若需要,设为 "true",此时 Origin 不能用 *)
        response["Access-Control-Allow-Credentials"] = "true"

        # 3. 返回添加了头的响应
        return response

步骤 2:注册自定义中间件

和方法一类似,在 settings.py 的 MIDDLEWARE 中添加自定义中间件,位置同样要靠前

# settings.py
MIDDLEWARE = [
    'myapp.middleware.CorsMiddleware',  # 新增:自定义 CORS 中间件
    'django.middleware.security.SecurityMiddleware',
    # ... 其他中间件
]

四、方法三:在视图中单独处理(个别场景)

如果只有少数几个视图需要跨域(比如开放给第三方的 API),没必要全局配置,直接在视图中手动添加响应头即可

示例:基于函数的视图

# myapp/views.py
from django.http import JsonResponse

def open_api_view(request):
    # 1. 处理业务逻辑(如返回数据)
    data = {"status": "success", "message": "这是开放的跨域 API"}
    response = JsonResponse(data)

    # 2. 手动添加 CORS 头(仅对当前视图生效)
    response["Access-Control-Allow-Origin"] = "https://thirdparty.com"  # 仅允许第三方域名
    response["Access-Control-Allow-Methods"] = "GET, OPTIONS"  # 仅允许 GET 和预检
    response["Access-Control-Allow-Headers"] = "Content-Type"

    # 3. 返回响应
    return response

示例:基于类的视图

# myapp/views.py
from django.views import View
from django.http import JsonResponse

class OpenApiView(View):
    def get(self, request):
        data = {"status": "success", "message": "类视图的跨域响应"}
        response = JsonResponse(data)
        # 添加 CORS 头
        response["Access-Control-Allow-Origin"] = "https://thirdparty.com"
        return response

五、前端配合:Vue + Axios 配置

跨域是前后端配合的问题,后端配置好后,前端需要确保请求参数正确(尤其是携带凭证时)

示例:Axios全局配置

在 Vue 项目的 main.js 或请求工具文件中配置:

// src/main.js 或 src/utils/request.js
import axios from 'axios';

// 1. 配置后端基础 URL(Django 服务地址)
axios.defaults.baseURL = 'http://127.0.0.1:8000';

// 2. 允许携带凭证(若后端 CORS_ALLOW_CREDENTIALS = True,必须设为 true)
axios.defaults.withCredentials = true;

// 3. 挂载到 Vue 原型(方便组件中使用)
Vue.prototype.$axios = axios;

示例:发送具体请求

// 在 Vue 组件中
export default {
  methods: {
    fetchData() {
      this.$axios.get('/api/data/')  // 后端接口
        .then(response => {
          console.log("跨域请求成功:", response.data);
        })
        .catch(error => {
          console.error("跨域请求失败:", error);
        });
    },

    submitData() {
      const postData = { name: "测试", value: "123" };
      this.$axios.post('/api/submit/', postData)
        .then(response => {
          console.log("POST 请求成功:", response.data);
        });
    }
  }
};

六、生产环境必须注意的 4 点

1、绝对禁止使用 CORS_ALLOW_ALL_ORIGINS = True

        开发环境用它方便调试,但生产环境会暴露所有接口,存在安全风险,必须用 CORS_ALLOWED_ORIGINS 指定具体域名

2、携带凭证时,Access-Control-Allow-Origin 不能用 *

        若 CORS_ALLOW_CREDENTIALS = TrueCORS_ALLOWED_ORIGINS 必须写具体域名(如 https://yourdomain.com),不能用通配符 *,否则浏览器会拒绝响应   

3、限制允许的方法和头部

只开放业务需要的 HTTP 方法(如不需要 DELETE 就删掉)和请求头,避免不必要的暴露

4、HTTPS 环境下的域名配置

        生产环境若用 HTTPS,CORS_ALLOWED_ORIGINS 中的域名必须带 https://(如 https://yourdomain.com),不能用 HTTP

七、常见问题及解决方案

问题 1:预检请求(OPTIONS)失败

现象:前端报错 “Preflight response is not successful”

原因:后端没有正确处理 OPTIONS 请求(预检请求)

解决

  • 方法一(推荐):用 django-cors-headers,它会自动处理 OPTIONS 请求,无需手动写逻辑
  • 方法二(自定义中间件):确保中间件对所有请求(包括 OPTIONS)都添加了 CORS 头

问题 2:携带凭证时请求被拦截

现象:前端 withCredentials: true,后端 CORS_ALLOW_CREDENTIALS = True,但报错 “Credentials flag is true, but Access-Control-Allow-Origin is not set”

原因Access-Control-Allow-Origin 用了 *,但携带凭证时不允许通配符

解决:在 settings.py 中用 CORS_ALLOWED_ORIGINS 替换 CORS_ALLOW_ALL_ORIGINS,指定具体域名

问题 3:自定义请求头不被允许

现象:前端传自定义头(如 X-Token),报错 “Request header field x-token is not allowed by Access-Control-Allow-Headers”

原因:后端 CORS_ALLOW_HEADERS 中没有包含这个自定义头

解决:在 settings.py 的 CORS_ALLOW_HEADERS 中添加 x-token(注意大小写一致)

八、总结

1、推荐场景:90% 的前后端分离项目用 方法一(django-cors-headers),配置简单、功能全面,兼顾开发和生产

2、特殊场景:不想依赖第三方库用 方法二(自定义中间件),少数视图跨域用 方法三(视图单独处理)

3、核心原则:生产环境优先保证安全,明确指定允许的域名、方法和头部,不滥用通配符

按照本文的步骤配置,你就能顺利解决 Django 的跨域问题,让前后端流畅通信!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐