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

Django1.11.9自定义中间件更新POST请求失效问题求助

问题根源分析

你遇到的问题核心在于Django原生请求对象和DRF请求对象的处理逻辑差异,以及ConvertTokenView内部的操作直接覆盖了你中间件添加的字段:

  1. DRF的request.data与Django原生request.POST的区别
    DRF的Request是对Django原生request的封装,request.data是从原始请求体(比如JSON、form-data等)解析而来,并不完全依赖request.POST。如果你的请求是JSON格式,request.POST本身就是空的,中间件修改它自然不会被DRF的request.data捕获。

  2. ConvertTokenView的覆盖操作
    在ConvertTokenView的post方法里,这段代码把request.data的内容全部覆盖到原生request.POST上:

    request._request.POST = request._request.POST.copy()
    for key, value in request.data.items():
        request._request.POST[key] = value
    

    这意味着不管你中间件给原生request.POST加了什么,都会被request.data里的原始内容覆盖——而request.data里本来就没有client_id和client_secret,所以最终这两个字段就消失了。

  3. 中间件执行顺序的潜在影响
    如果你的LoginMiddleware放在DRF的RequestMiddleware之后,DRF已经提前解析完request.data了,这时候你修改原生request.POST也不会同步到request.data里。


解决方案

根据你的需求,这里有几个可行的方案,按推荐程度排序:

方案1:在中间件中直接修改DRF的request.data

判断当前请求是否是DRF的请求对象,如果是,直接给request.data添加字段,同时同步修改原生request.POST以兼容普通Django视图:

class LoginMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 处理DRF请求的data字段
        if hasattr(request, 'data'):
            # 先复制为可修改对象(避免QueryDict不可变的问题)
            mutable_data = request.data.copy()
            mutable_data['client_id'] = '12345678'
            mutable_data['client_secret'] = '12345678'
            request.data = mutable_data
        
        # 处理原生Django请求的POST字段
        request.POST = request.POST.copy()
        request.POST['client_id'] = '12345678'
        request.POST['client_secret'] = '12345678'

        response = self.get_response(request)
        return response

方案2:修改ConvertTokenView,在覆盖后添加字段

既然ConvertTokenView会覆盖request.POST,那可以在它覆盖完成后再把client_id和client_secret加进去,这样就不会被冲掉:

class ConvertTokenView(CsrfExemptMixin, OAuthLibMixin, APIView):
    # 保留原有属性配置
    server_class = SocialTokenServer
    validator_class = oauth2_settings.OAUTH2_VALIDATOR_CLASS
    oauthlib_backend_class = KeepRequestCore
    permission_classes = (permissions.AllowAny,)

    def post(self, request, *args, **kwargs):
        import pdb ; pdb.set_trace()
        # 使用rest framework的`.data`模拟django请求的POST主体
        request._request.POST = request._request.POST.copy()
        for key, value in request.data.items():
            request._request.POST[key] = value
        
        # 在这里添加字段,避免被之前的循环覆盖
        request._request.POST['client_id'] = '12345678'
        request._request.POST['client_secret'] = '12345678'

        url, headers, body, status = self.create_token_response(request._request)
        response = Response(data=json.loads(body), status=status)
        for k, v in headers.items():
            response[k] = v
        return response

这个方案不需要修改中间件,但缺点是需要自定义ConvertTokenView,后续依赖包更新时需要同步维护。

方案3:修改原始请求体(适合JSON格式请求)

如果你的请求是JSON格式,DRF是从request.body解析request.data的,所以可以在中间件中直接修改原始请求体内容:

import json

class LoginMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 只处理POST请求且为JSON格式的情况
        if request.method == 'POST' and request.content_type == 'application/json':
            try:
                body_data = json.loads(request.body)
                body_data['client_id'] = '12345678'
                body_data['client_secret'] = '12345678'
                # 重新构造request.body
                request.body = json.dumps(body_data).encode('utf-8')
                # 同步更新POST字段兼容非DRF视图
                request.POST = request.POST.copy()
                request.POST['client_id'] = '12345678'
                request.POST['client_secret'] = '12345678'
            except json.JSONDecodeError:
                # 处理解析失败的情况(比如非JSON的POST请求)
                pass

        response = self.get_response(request)
        return response

这个方案最底层,能确保DRF解析request.data时就能拿到字段,但需要处理不同的请求格式(比如form-data),相对复杂。


注意事项
  • 确保你的LoginMiddleware在DRF的中间件之前注册(在settings.py的MIDDLEWARE列表中,放在rest_framework.middleware.RequestMiddleware之前),这样中间件的修改才能被DRF的解析逻辑捕获。
  • 如果使用方案1,要注意request.data可能是不可变的QueryDict,必须先复制再修改。

内容的提问来源于stack exchange,提问作者Vadim Vzorov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:38:10