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

使用requests向Tastypie接口发送含JSON和zip的multipart请求报错如何解决

问题结论

首先明确:可以通过multipart/form-data内容类型同时传输JSON数据与zip文件,你遇到的报错均为代码逻辑错误导致,和协议本身的能力无关。

报错原因
  1. 服务端utf-8解码报错:你直接对整个multipart/form-data请求的request.body做JSON解析,该请求体同时包含JSON文本段和zip二进制内容,不是纯JSON字符串,直接解析必然失败。
  2. 客户端无可用反序列化方法报错:Tastypie默认的Serializer未注册multipart/form-data对应的格式映射,无法识别该内容类型。
修复方案

1. 服务端先添加自定义Serializer支持multipart格式

from tastypie.serializers import Serializer
import json

class CustomSerializer(Serializer):
    # 扩展支持multipart格式
    formats = Serializer.formats + ['multipart']
    content_types = dict(Serializer.content_types, **{
        'multipart': 'multipart/form-data'
    })

2. 修正MultipartResource的反序列化逻辑

class MultipartResource(object):
    class Meta:
        # 指定使用自定义Serializer,解决无反序列化方法的问题
        serializer = CustomSerializer()

    def deserialize(self, request, data, format=None):
        try:
            if not format:
                format = request.META.get('CONTENT_TYPE', 'application/x-www-form-urlencoded')
            if format == 'application/x-www-form-urlencoded':
                return request.POST
            if 'multipart' in format:
                data = request.POST.copy()
                data.update(request.FILES)
                # 修正:从POST的JSON字段取内容解析,不要直接解析整个request.body
                payload = json.loads(data.get('JSON', '{}'))
                # 注意和客户端传的文件key保持一致,客户端传的是Console不是ADB
                zip_obj = TestZipModel()
                zip_obj.ADB = request.FILES['Console']
                zip_obj.save()
                # 解析后的业务参数放入data,供后续逻辑调用
                data['payload'] = payload
                return data
        except Exception as e:
            print("Error {}".format(e))
        return super(MultipartResource, self).deserialize(request, data, format)

    def obj_create(self, bundle, request=None, **kwargs):
        pass

3. 客户端代码无需大幅修改,仅需注意字段名和服务端对齐即可。

更优实现方案

如果你的业务参数是扁平的简单结构,无需嵌套,可以直接用普通表单字段传参数,省去JSON序列化/反序列化步骤,代码更简洁:

客户端修改

def sendLogs():
    url = "api/ziprel/"
    # 直接用data参数传业务参数,无需包装为JSON
    payload = {"param_1": "value_1","param_2": "value_2"}
    files = {
        'Console': (os.path.basename('/home/pi/Desktop/Console.zip'), open('/home/pi/Desktop/Console.zip','rb'), 'application/zip')
    }
    # requests同时传data和files时会自动使用multipart/form-data格式
    r = requests.post(url, data=payload, files=files)
    print(r.content)

服务端适配

不需要再解析JSON,直接从request.POST['param_1']、request.POST['param_2']即可取到业务参数,适合大部分简单场景。如果你的业务参数是复杂嵌套结构,仍可以使用之前传JSON字段的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 02:36:04