Django REST Framework自定义X-API-Version头触发CORS错误
自定义请求头X-API-Version引发CORS错误的解决方法
问题背景
尝试通过自定义请求头X-API-Version校验前端版本,但配置django-cors-headers后仍触发CORS错误,错误信息如下:
Access to XMLHttpRequest at 'http://192.168.5.39:8001/api/host/login/'
from origin 'http://localhost:9000' has been blocked by CORS policy:
Request header field x-api-version is not allowed by Access-Control-Allow-Headers
in preflight response.
已完成以下配置但无效:
- 安装并注册
django-cors-headers到INSTALLED_APPS - 中间件中添加
corsheaders.middleware.CorsMiddleware和django.middleware.common.CommonMiddleware - 将
x-api-version加入CORS_ALLOW_HEADERS - 设置
CORS_ORIGIN_ALLOW_ALL = True
核心问题分析
从提供的配置文件看,两个关键问题导致了错误:
- 中间件顺序错误:
corsheaders.middleware.CorsMiddleware必须放在所有其他中间件之前,否则自定义中间件会在CORS预检校验前拦截请求,导致响应头中未包含允许的自定义头。 - 版本校验中间件未跳过预检请求:OPTIONS预检请求未被版本校验逻辑跳过,直接返回401,导致CORS校验失败。
- 中间件初始化方法语法错误:原
VersionAPIMiddleware中的_init_和_call_是单下划线,不符合Python类特殊方法的双下划线规范,导致中间件无法正常工作。
解决方案
1. 调整中间件顺序
修改MIDDLEWARE列表,将CORS中间件移至最顶部,确保它优先处理所有请求:
MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # 优先处理CORS逻辑 'django.middleware.common.CommonMiddleware', 'api.middleware.VersionAPIMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
2. 修复版本校验中间件
修改VersionAPIMiddleware,修复语法错误并跳过OPTIONS预检请求:
from nome_api.settings import VERSION from django.http import JsonResponse class VersionAPIMiddleware: def __init__(self, get_response): # 修正为双下划线的特殊方法 self.get_response = get_response def __call__(self, request): # 修正为双下划线的特殊方法 # 跳过OPTIONS预检请求,让CORS中间件处理 if request.method == 'OPTIONS': return self.get_response(request) ver_request = int(request.META.get('HTTP_X_API_VERSION', 0)) # 加载swagger和admin页面时跳过校验 if len(request.path) == 1 or '/admin/' in request.path or '/swagger/' in request.path: response = self.get_response(request) return response # 校验API版本 if ver_request == VERSION: response = self.get_response(request) return response else: # swagger请求跳过校验 if 'HTTP_X_CSRFTOKEN' in request.META: response = self.get_response(request) return response else: return JsonResponse({'msg': 'favor atualizar o aplicativo'}, status=401)
3. 简化CORS_ALLOW_HEADERS配置
只需要添加小写的x-api-version即可,无需重复添加不同格式的版本:
from corsheaders.defaults import default_headers CORS_ALLOWED_HEADERS = list(default_headers) + ['x-api-version']
验证步骤
- 重启Django服务
- 发送带
X-API-Version头的请求,检查是否仍有CORS错误 - 查看OPTIONS预检请求的响应头,确认
Access-Control-Allow-Headers中包含x-api-version
内容的提问来源于stack exchange,提问作者rbrayner
相关产品推荐
相关产品推荐

