You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NGINX+Django DRF+Vue.js中POST请求返回405(GET不允许)问题求助

405 Method Not Allowed 问题排查与解决

问题场景

线上电商网站提交联系表单时返回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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 23:37:06