NGINX+Django DRF+Vue.js中POST请求返回405(GET不允许)问题求助
问题场景
线上电商网站提交联系表单时返回405 Method Get not allowed错误,实际发起的是POST请求;本地运行无此问题,且部分表单(如结账表单)线上可正常工作。前端使用axios.post('/api/v1/contacto/', data)提交请求。
可能原因与解决方案
1. 请求重定向导致POST转GET
这是最常见的触发原因:如果前端请求的URL不带结尾斜杠(如/api/v1/contacto),而Django后端URL配置带斜杠(path('contacto/', ...)),Django会返回301重定向到带斜杠的URL,浏览器会自动将POST请求转为GET请求,最终触发405错误。
解决方法:
- 确保前端请求URL带结尾斜杠:确认
axios.post('/api/v1/contacto/', data)中的路径末尾包含/ - 若需兼容无斜杠请求,可在Django设置中关闭自动追加斜杠:
APPEND_SLASH = False(不推荐,会破坏Django默认URL规范)
2. Nginx代理路径配置错误
当前Nginx配置中proxy_pass http://ecologic_app_server/api/v1/;结合location /api/v1/,会将/api/v1/contacto/代理为http://ecologic_app_server/api/v1/contacto/,若后端Django主URL已包含api/v1/,路径是正确的;但如果后端路由结构不同,可能导致路径不匹配。
修正建议:
将proxy_pass改为不带后缀的路径,避免重复:
location /api/v1/ { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-NginX-Proxy true; proxy_set_header Host $http_host; proxy_pass http://ecologic_app_server; # 去掉末尾的/api/v1/ proxy_ssl_session_reuse off; proxy_redirect off; }
修改后重启Nginx:sudo systemctl restart nginx
3. 视图函数逻辑漏洞
当前视图函数存在逻辑问题:无论表单数据是否验证通过,都会返回201状态码,虽不直接引发405,但会影响错误调试。
修正后的视图代码:
@api_view(['POST']) def contact_form_post(request): serializer = ContactForm(data=request.data) if serializer.is_valid(): first_name = serializer.validated_data['first_name'] last_name = serializer.validated_data['last_name'] phone = serializer.validated_data['phone'] email = serializer.validated_data['email'] subject = serializer.validated_data['subject'] message = serializer.validated_data['message'] print(first_name, last_name, phone, email, subject, message) context = { 'first_name': first_name, 'last_name': last_name, 'phone': phone, 'email': email, 'subject': subject, 'message': message } html = render_to_string('emails/contact.html', context) text = render_to_string('emails/contact.txt', context) recipient = MainSettings.objects.first().contact_email send_mail( subject, message=text, html_message=html, from_email=settings.DEFAULT_FROM_EMAIL, recipient_list=[recipient], fail_silently=False, ) serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
4. 验证请求真实状态
通过Nginx日志确认请求的真实方法和路径:
tail -f /var/log/nginx/access.log
提交表单后查看日志记录,若显示为GET /api/v1/contacto,则可确认是重定向导致的方法转换。
5. 其他检查点
- 确认Django的
ALLOWED_HOSTS配置包含线上服务器的IP或域名,避免Host不匹配导致的请求异常 - 重启后端服务和Nginx,确保所有配置生效:
sudo systemctl restart gunicorn sudo systemctl restart nginx
内容的提问来源于stack exchange,提问作者Ivan Stepanchuk

