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

Django REST Framework日志过滤器中无法访问request.data如何解决

错误原因

你的代码触发RawPostDataException的核心逻辑是:

  • Django原生HttpRequest的请求体数据流是一次性的,读取后就会被消费无法二次读取
  • DRF的Request对象的data属性首次访问时会解析请求体流,解析完成后流就为空
  • 你在日志Filter中每次都重新实例化DRF Request对象,这个新实例没有缓存之前视图已经解析好的请求体数据,访问request.data时会尝试重读已经被消费的流,就会抛出异常

解决方案

最稳妥的方案是通过中间件提前缓存解析好的请求体,避免重复读取流:

第一步:新增请求体缓存中间件

# 可放在对应app的middlewares.py文件中
from django.utils.deprecation import MiddlewareMixin
from rest_framework.request import Request
from rest_framework.settings import api_settings

class CacheRequestBodyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        # 跳过文件上传类请求,避免大文件占用过多内存
        if request.content_type.startswith('multipart/'):
            request.cached_data = {}
            return
        # 仅解析一次请求体,缓存到原生HttpRequest对象上
        drf_request = Request(
            request,
            parsers=[parser() for parser in api_settings.DEFAULT_PARSER_CLASSES],
            authenticators=[auth() for auth in api_settings.DEFAULT_AUTHENTICATION_CLASSES]
        )
        try:
            request.cached_data = drf_request.data
        except Exception:
            # 解析失败时给空值,避免影响正常业务逻辑
            request.cached_data = {}

第二步:注册中间件

在settings.py的MIDDLEWARE列表最顶部添加该中间件:

MIDDLEWARE = [
    '你的应用名.middlewares.CacheRequestBodyMiddleware', # 放在列表第一位
    'django.middleware.security.SecurityMiddleware',
    # 其他原有中间件保持不变
]

第三步:修改日志Filter逻辑

直接读取缓存好的请求体数据,不需要再实例化DRF Request:

import logging

class RequestInfoFilter(logging.Filter):
    def filter(self, record):
        request = record.request
        record.method = request.method
        record.query_params = request.GET.dict()
        # 直接拿缓存好的data,不会重读流
        record.data = request.cached_data
        return True

补充说明

如果不想新增中间件,也可以在原有Filter中添加异常捕获兜底,避免日志逻辑影响业务,该方案仅适合临时调试使用,缺陷是如果视图已经读取过请求体,日志中就拿不到请求数据:

import logging

from rest_framework.request import Request
from rest_framework.settings import api_settings


class RequestInfoFilter(logging.Filter):

    def filter(self, record):
        parsers = [parser() for parser in api_settings.DEFAULT_PARSER_CLASSES]
        authenticators = [
            auth() for auth in api_settings.DEFAULT_AUTHENTICATION_CLASSES]
        request = Request(
            record.request, parsers=parsers, authenticators=authenticators)

        record.method = request.method
        record.query_params = request.query_params
        try:
            record.data = request.data
        except Exception:
            record.data = {}

        return True

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 02:54:02