Django CORS Headers对POST请求失效,求解决方法
问题分析与解决方案
问题核心原因
GET属于简单请求,浏览器不会发送预检OPTIONS请求,直接执行请求并校验返回头;而POST(尤其是带自定义头或非默认Content-Type的POST)属于非简单请求,浏览器会先发送OPTIONS预检请求,确认服务器允许该请求方法、头信息后才会发送实际POST请求。你遇到的问题本质是OPTIONS预检请求未被正确处理,导致浏览器判定CORS不通过。
分步解决步骤
1. 修正Django中间件顺序
django-cors-headers的中间件必须放在最前面(至少在CommonMiddleware之前),否则无法正确拦截并处理预检请求:
# settings.py MIDDLEWARE = [ "corsheaders.middleware.CorsMiddleware", # 必须放在首位 "django.middleware.common.CommonMiddleware", # 其他中间件(如CsrfViewMiddleware等)放在后面 ]
2. 补全Django CORS配置
确保settings.py中CORS相关配置完整,覆盖必要的规则:
# settings.py # 指定允许的前端域名(生产环境禁用CORS_ALLOW_ALL_ORIGINS,用具体域名更安全) CORS_ALLOWED_ORIGINS = [ "https://你的前端域名.com", ] # 显式声明允许的请求方法(默认已包含POST,配置后更清晰) CORS_ALLOW_METHODS = ("DELETE", "GET", "OPTIONS", "PATCH", "POST", "PUT") # 允许前端传递的请求头(根据实际业务添加,比如Content-Type、Authorization) CORS_ALLOW_HEADERS = ("Content-Type", "Authorization") # 如果前端请求需要携带Cookie,开启此项 CORS_ALLOW_CREDENTIALS = True
3. 调整Apache配置,确保OPTIONS请求被正确转发
当前Apache配置未处理OPTIONS预检请求,可能直接拦截导致无法到达Django。在VirtualHost中添加以下规则:
<VirtualHost *:443> ServerName [...] # 新增处理OPTIONS请求的规则 <Location "/"> Require all granted # 若Django已通过cors-headers处理CORS,可注释以下Header配置避免重复 # Header always set Access-Control-Allow-Origin "https://你的前端域名.com" # Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, PUT, DELETE, PATCH" # Header always set Access-Control-Allow-Headers "Content-Type, Authorization" # 让OPTIONS请求直接返回200(或转发给Django处理) RewriteEngine On RewriteCond %{REQUEST_METHOD} OPTIONS RewriteRule ^(.*)$ $1 [R=200,L] </Location> ProxyPass /.well-known ! ProxyPass / http://localhost:8000/ ProxyPassReverse / http://localhost:8000/ ProxyPreserveHost On # 原有SSL配置... SSLEngine on SSLCertificateFile /etc/letsencrypt/live/[...]/cert.pem SSLCertificateKeyFile /etc/letsencrypt/live/[...]/privkey.pem SSLCertificateChainFile /etc/letsencrypt/live/[...]/fullchain.pem Alias /.well-known [...]/www/.well-known/ <Directory [...]/www/.well-known> Options FollowSymLinks MultiViews AllowOverride All Require all granted </Directory> LogLevel debug ErrorLog [...]/logs/error.log CustomLog [...]/logs/access.log combined </VirtualHost>
4. 验证请求链路
查看Django的日志文件,确认OPTIONS请求是否被接收并处理:
- 如果日志中存在OPTIONS请求记录,说明问题出在Django的CORS配置,重新核对
CORS_ALLOWED_ORIGINS等参数; - 如果日志中没有OPTIONS请求,说明Apache未转发该请求,需重新检查Apache的Rewrite规则和Proxy配置。
内容的提问来源于stack exchange,提问作者Jbb
相关产品推荐
相关产品推荐

