返回非200状态码时出现CORS错误(Django+ReactJS)
Django返回401时React触发CORS报错的解决方法
问题场景
Django后端返回401(未授权)状态码时,React前端触发CORS报错;改为返回200状态码可正常运行,但业务需求必须返回401。
报错信息
Access to fetch at 'http://localhost:8888/employees/api/fetch/home/data/' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
前端React请求代码
export async function post(url, requestBody = {}, token=true) { try{ const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', 'token' : token ? window.sessionStorage.getItem("token") : null, 'user-type' : token ? window.sessionStorage.getItem("user-type") : null, 'identifier' : token ? window.sessionStorage.getItem("identifier") : null, }, body: requestBody ? JSON.stringify(requestBody) : "{}" }; console.log("Requesting POST : url is : ", url," Content Is: ", requestOptions) const response = await fetch(url, requestOptions); return await response.json() }catch(e){ console.log("Service Failed: ", e) return { status: false, messages: ["Service Failed. Please try after sometime."] } } }
后端Django配置(settings.py)
#TODO CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", ] CUSTOM_HEADERS = ( 'Access-Control-Allow-Origin', 'token', 'user-type', 'identifier', 'device-id', 'is-mobile' ) CORS_ALLOW_HEADERS = default_headers + CUSTOM_HEADERS #TODO CORS_ORIGIN_ALLOW_ALL = True #TODO CORS_ORIGIN_WHITELIST = ( 'http://localhost:3000', ) #TODO ALLOWED_HOSTS = [ '127.0.0.1', 'localhost', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'middleware.authenticate.Authenticate', #Cors 'corsheaders.middleware.CorsMiddleware', ]
Django响应构建函数
def build_response(response_code, message, data=None): if (message == None or message == ""): message = [] else: if (hasattr(message, '__len__') and (not isinstance(message, str))): pass else: message = [message] fdata = { "status" : True if response_code < 300 else False, "messages" : message, "data" :data } resp = Response(fdata, response_code) cust_headers = (','.join(str(each_hdr) for each_hdr in CUSTOM_HEADERS)) allowed_origins = (','.join(str(each_origin) for each_origin in CORS_ALLOWED_ORIGINS)) resp['Access-Control-Allow-Origin'] = allowed_origins resp["Access-Control-Allow-Headers"] = 'X-Requested-With, Content-Type, '+cust_headers return resp
解决方法
- 调整中间件顺序:
corsheaders.middleware.CorsMiddleware必须放在所有其他中间件最前面,尤其是自定义的认证中间件。预检请求(OPTIONS)需要先被CORS中间件处理返回200,不能被认证中间件拦截返回401。修改后的MIDDLEWARE顺序:MIDDLEWARE = [ # Cors中间件前置 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'middleware.authenticate.Authenticate', ] - 跳过OPTIONS请求的认证检查:在自定义的
middleware.authenticate.Authenticate中间件中,直接放行OPTIONS请求,避免触发401:class Authenticate(MiddlewareMixin): def process_request(self, request): if request.method == 'OPTIONS': return None # 原有认证逻辑... - 清理冗余CORS配置:
CORS_ORIGIN_ALLOW_ALL = True已覆盖CORS_ALLOWED_ORIGINS和CORS_ORIGIN_WHITELIST,建议保留CORS_ALLOWED_ORIGINS并设置CORS_ORIGIN_ALLOW_ALL = False,提升安全性。 - 移除响应中手动添加的CORS头:corsheaders库会自动处理CORS响应头,无需在
build_response函数中手动添加,避免重复或错误配置。
内容的提问来源于stack exchange,提问作者Aravind Pillai
相关产品推荐
相关产品推荐

