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

如何在Django Rest Framework中处理带gzip压缩体的POST请求

解决方案:DRF处理gzip压缩的JSON请求体

首先纠正前端代码的错误:你的前端代码中,axios.post的请求体传的是原始的data,而非压缩后的gz_data,这会导致后端根本没收到压缩数据,先修正这一点:

async postData(json_data) {
    let headers = authHeader();
    headers['Content-Encoding'] = 'gzip';
    headers['Content-Type'] = 'application/json';

    const data = json_data;
    const gz_data = pako.gzip(JSON.stringify(data));
    
    return axios
      .post(API_URL + 'create/', 
        gz_data, // 这里改成gz_data,不是原始data
        {
          headers: headers,
        }
      )
      .then(response => {
        return response.data;
      })
  }

接下来解决后端的解压问题,提供两种可行方案:

方案一:自定义DRF解析器(视图级控制,推荐)

继承DRF的JSONParser,添加gzip解压逻辑,仅在需要的视图中使用该解析器:

import zlib
import io
from rest_framework.parsers import JSONParser
from rest_framework.exceptions import ParseError

class GzipJSONParser(JSONParser):
    def parse(self, stream, media_type=None, parser_context=None):
        parser_context = parser_context or {}
        request = parser_context.get('request')
        encoding = request.headers.get('Content-Encoding', '')
        
        # 仅处理gzip编码的请求
        if 'gzip' in encoding.lower():
            try:
                # 读取压缩数据并解压
                compressed_data = stream.read()
                # 限制解压后大小,防止gzip炸弹(示例限制为10MB)
                decompressed_data = zlib.decompress(compressed_data, zlib.MAX_WBITS | 16)
                if len(decompressed_data) > 10 * 1024 * 1024:
                    raise ParseError("Decompressed data exceeds size limit")
                # 将解压后的数据转为类文件对象,交给父类解析JSON
                stream = io.BytesIO(decompressed_data)
            except zlib.error as e:
                raise ParseError(f"Failed to decompress gzip data: {str(e)}")
        
        # 调用父类的parse方法解析JSON
        return super().parse(stream, media_type, parser_context)

然后在你的视图中指定使用这个解析器:

from rest_framework import generics

class DataList(generics.ListCreateAPIView):
    serializer_class = DataSerializer
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    parser_classes = [GzipJSONParser]  # 添加这一行指定解析器

    def get_queryset(self):
        return Data.objects.filter(user=self.request.user)
    
    def post(self, request, format=None):
        transect_data = request.data  # 现在可以正常获取解析后的JSON数据
        # 后续业务逻辑...

方案二:Django中间件(全局生效)

如果需要全局处理所有gzip压缩的JSON请求,可以编写一个中间件,在请求到达DRF之前解压请求体:

import zlib
from django.http import BadRequest

class GzipRequestMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        encoding = request.headers.get('Content-Encoding', '')
        content_type = request.headers.get('Content-Type', '')
        
        # 仅处理Content-Type为application/json且Content-Encoding包含gzip的请求
        if 'gzip' in encoding.lower() and 'application/json' in content_type.lower():
            try:
                # 读取压缩数据
                compressed_data = request.body
                # 解压并限制大小(示例限制为10MB)
                decompressed_data = zlib.decompress(compressed_data, zlib.MAX_WBITS | 16)
                if len(decompressed_data) > 10 * 1024 * 1024:
                    return BadRequest("Decompressed data exceeds size limit")
                # 替换request的body为解压后的数据
                request._body = decompressed_data
                # 更新Content-Encoding,避免后续中间件重复处理
                updated_encoding = request.META['HTTP_CONTENT_ENCODING'].replace('gzip', '').strip()
                if updated_encoding:
                    request.META['HTTP_CONTENT_ENCODING'] = updated_encoding
                else:
                    del request.META['HTTP_CONTENT_ENCODING']
            except zlib.error:
                return BadRequest("Invalid gzip compressed data")
        
        response = self.get_response(request)
        return response

然后在settings.py的MIDDLEWARE列表中添加这个中间件(注意要放在DRF相关中间件之前):

MIDDLEWARE = [
    # ... 其他中间件
    'your_app.middleware.GzipRequestMiddleware',  # 替换为你的中间件实际路径
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'rest_framework.authentication.SessionAuthentication',
    # ...
]

安全注意事项

  • 强制大小限制:必须限制解压后的数据大小,避免恶意构造的gzip炸弹耗尽服务器资源
  • 严格校验请求头:只处理Content-Type为application/json且Content-Encoding包含gzip的请求
  • 仅信任可信客户端:确保只有你的前端应用发送此类压缩请求,避免未知来源的恶意请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 22:24:20