React+Django同端口部署POST请求403/500错误求助
问题分析与解决方案
一、403 Forbidden 问题根源
当前后端同端口运行时,请求属于同域请求,Django的CSRF中间件会严格校验请求的CSRF令牌——你之前跨端口时依赖CORS配置绕过了校验,但同域下CORS规则不适用,必须正确携带CSRF令牌。
解决步骤:
前端携带CSRF令牌
- 先在Django返回的
index.html模板中注入CSRF令牌(因为是通过TemplateView渲染的页面):<script> window.CSRF_TOKEN = "{{ csrf_token }}"; </script> - 修改axios请求,在请求头中添加
X-CSRFToken:const handleSubmit = async (formData) => { try { const response = await axios.post( '/backend/api/create_message/', // 同域下用相对路径更稳妥 formData, { headers: { 'X-CSRFToken': window.CSRF_TOKEN } } ); console.log('Message sent successfully:', response.data); } catch (error) { console.error('Error sending message:', error); } }; - 也可以全局配置axios自动从cookie读取CSRF令牌(Django默认会把令牌存在
csrftokencookie中):import axios from 'axios'; axios.defaults.xsrfCookieName = 'csrftoken'; axios.defaults.xsrfHeaderName = 'X-CSRFToken';
- 先在Django返回的
调整CORS中间件顺序
你的MIDDLEWARE配置中,CorsMiddleware放在了CsrfViewMiddleware之后,会导致CSRF校验先执行,CORS规则失效。正确顺序应该把CorsMiddleware移到最前面:MIDDLEWARE = [ "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', ]
二、加@csrf_exempt后500错误的原因及解决
错误根源:
messages框架依赖Session和CSRF上下文:视图中使用的messages.success()/messages.warning()依赖Django的Session中间件和CSRF上下文,@csrf_exempt会跳过CSRF校验,导致Session上下文异常,无法正常使用messages。- 邮件配置占位符未替换:代码中
recipient_list = ['email']是占位符,实际运行时会触发邮件发送异常。 - 混合视图逻辑冲突:用
@api_view标记的DRF视图,同时返回render()渲染模板,这种混合写法会导致请求上下文不一致。
解决步骤:
- 移除
@csrf_exempt:按照上述方法正确处理CSRF令牌,无需禁用校验。 - 修复邮件配置:把
recipient_list替换为真实收件邮箱:recipient_list = ['your-real-email@example.com'] - 调整视图逻辑(可选):如果是给前端提供API接口,建议返回JSON响应而非模板渲染,更符合前后端分离设计:
@api_view(['POST', 'GET']) def create_message(request): if request.method == 'POST': serializer = MessageSerializer(data=request.data) if serializer.is_valid(): serializer.save() # 邮件发送逻辑... return Response({"status": "success", "message": "Message successfully sent"}, status=200) return Response({"status": "error", "message": "Message not sent"}, status=400) # GET请求如需返回表单,可根据需求保持或改为JSON响应 form = MessageForm() context = {'form': form} template = '../templates/lpadj/message_form.html' return render(request, template, context)
额外注意事项
- 同域请求尽量用相对路径,避免硬编码绝对路径,减少环境切换时的配置问题。
- 检查
settings.py中SESSION_COOKIE_DOMAIN和CSRF_COOKIE_DOMAIN,同域下保持默认即可。
内容的提问来源于stack exchange,提问作者Vik
相关产品推荐
相关产品推荐

