Django REST Framework如何以POST请求重定向到其他ViewSet
问题根因
默认的redirect和HttpResponseTemporaryRedirect返回的都是302状态码,主流浏览器收到302响应后会自动将后续重定向请求改为GET方法、丢弃原请求体,所以才会出现POST接口报405、request.data为空的问题。
解决方法
方案1:307状态码重定向(适配客户端跳转场景)
307状态码的规范明确要求重定向时不得修改原请求方法,且必须完整传递请求体,可以完美解决请求方法被篡改、参数丢失的问题,代码示例如下:
from django.http import HttpResponse import json from django.urls import reverse class GoogleViewSet(APIView): permission_classes = (permissions.AllowAny,) def post(self, request): password = User.objects.make_random_password() # 构造307重定向响应 response = HttpResponse( json.dumps({'email': 'test@test.com', 'username': 'test', 'password': password}), status=307, content_type="application/json" ) # 配置重定向目标地址 response['Location'] = reverse('v1_users:user_create') return response
注意:该方案依赖请求客户端支持307状态码,目前所有主流浏览器、HTTP客户端都已兼容,仅极老版本的客户端可能存在适配问题。
方案2:服务端内部直接调用逻辑(更推荐,无兼容问题)
如果不需要经过客户端跳转,完全可以在服务端内部直接调用UserViewSet的创建逻辑,性能更高、没有兼容风险,代码示例如下:
from rest_framework.request import Request from rest_framework.parsers import JSONParser class GoogleViewSet(APIView): permission_classes = (permissions.AllowAny,) def post(self, request): password = User.objects.make_random_password() user_data = {'email': 'test@test.com', 'username': 'test', 'password': password} # 构造适配UserViewSet的请求对象 new_request = Request( request=request._request, parsers=[JSONParser()], authenticators=request.authenticators ) new_request._full_data = user_data # 直接调用UserViewSet的create方法返回响应 return UserViewSet().create(new_request)
优化建议:如果UserViewSet的create方法有权限、限流等不需要在谷歌登陆场景触发的校验,可以把用户创建的核心逻辑抽为独立公共函数,两个接口分别调用即可,逻辑更解耦。
内容的提问来源于stack exchange,提问作者Headmaster
相关产品推荐
相关产品推荐

