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

Django REST Framework经Postman上传大CSV/ZIP文件损坏问题求助

问题环境
  • 系统环境:Windows
  • 技术栈:Django 4.0.6(Python 3.8)、djangorestframework 3.13.1
  • 测试环境:本地localhost环境,使用最新版Postman搭配Postman Agent测试接口
  • 接口需求:单次请求同时提交3个CSV文件、1个ZIP文件,附带2个文本字段参数;接口采用JWT鉴权,当前鉴权逻辑运行正常
异常现象

测试时仅体积最小的CSV文件可正常上传保存,大体积CSV、ZIP文件上传后均出现损坏:

  • 大体积CSV文件后半部分出现乱码,乱码字符形如:Û™eÞqHÂÔpŠl°‹<û yj­Ïª›kÃx›Ûr-¥x¡S¼à2SÕkÛår'mÒÕµd5ÿ¶Vê0@1 ̦Záë1§ŠIÇaÎ
    “’ÏÛ€t»vRoT"·‡Qf„¾´é-Oa)]ЧK‹5C¤sWB0),3 Zž—2¸Ñóo«jŸH“
  • 上传的ZIP文件无法正常解压打开
    已检索大量相关技术资料,未找到适配当前场景的解决方案,需要可行的修复建议。
相关代码与配置

模型定义代码

class FileUploader(models.Model):
    id_file = models.AutoField('id_file', primary_key=True)
    Campaign_Name = models.CharField('Campaign_Name', max_length=255)
    ViewpointSurvey = models.FileField('ViewpointSurvey',upload_to=path_and_rename_base,max_length=255,blank=False,null=False,db_column='ViewpointSurvey', name='ViewpointSurvey')
    ProjectSurvey = models.FileField('ProjectSurvey', upload_to=path_and_rename_base, max_length=255, blank=False, null=False,
                            db_column='ProjectSurvey', name='ProjectSurvey')
    Trajectories = models.FileField('Trajectories', upload_to=path_and_rename_base, max_length=255, blank=False, null=False,
                            db_column='Trajectories', name='Trajectories')
    screenshots = models.FileField('screenshots', upload_to=path_and_rename_base, max_length=255, blank=False,
                                    null=False,
                                    db_column='screenshots', name='screenshots')
    timestamp=models.DateTimeField('timestamp',auto_now_add=True,db_column='timestamp', name='timestamp')
    id_project=models.CharField('id_project', max_length=255)
    class Meta:
        db_table = "file_uploader"
        verbose_name_plural = 'file_uploader'
        verbose_name = "file_uploader"

视图定义代码

class CSVUploadAPI(GenericAPIView):
    parser_classes = [MultiPartParser]
    serializer_class = UploadSerializer

    def put(self, request):
        data_collect = request.data
        serializer = UploadSerializer(data=data_collect)
        if serializer.is_valid():
            serializer.save()
            return Response('Done')
        else:
            return Response(UploadSerializer.errors,status=status.HTTP_400_BAD_REQUEST)

序列化器定义代码

class UploadSerializer(serializers.ModelSerializer):
    class Meta:
        model= FileUploader
        fields = ('id_project','ProjectSurvey','Trajectories','ViewpointSurvey','screenshots','Campaign_Name')

文件存储重命名函数

def path_and_rename_base(instance, filename):
    upload_to = 'files/'
    ext = filename.split('.')[-1]
    # 文件名替换为随机UUID
    filename = '{}.{}'.format(uuid.uuid4(), ext)    
    return os.path.join(upload_to, filename)

配置核对说明

  • 已完成Postman请求头、请求体格式配置
  • 测试文件大小对照:仅文件列表中高亮的最小体积CSV可正常上传,其余大体积CSV、ZIP文件上传后均损坏

修复方案

按优先级逐一排查,可覆盖绝大多数同类大文件上传损坏场景:

  1. 排查请求体被提前读取/错误转义问题
    检查项目所有自定义中间件、视图装饰器,是否存在视图执行前调用request.body并将其转为字符串、做HTML转义/特殊字符替换的逻辑。二进制文件流一旦被按文本编码(如utf-8)读取,非文本字节会被解码为乱码,部分特殊字符会被转义为&quot;这类HTML实体,和当前出现的乱码特征完全匹配。如果有日志打印等必须读取请求体的场景,读取后必须重置request.META['wsgi.input']的指针位置,避免后续解析器拿到损坏的流数据。
  2. 调整Django上传配置阈值
    在settings.py中补充以下配置,避免文件超过内存阈值转存临时文件时出现截断:
    # 单次请求允许的总内容大小,可根据业务需求调整,示例为100MB
    DATA_UPLOAD_MAX_MEMORY_SIZE = 104857600
    # 单文件超过该大小时写入临时文件,示例为10MB
    FILE_UPLOAD_MAX_MEMORY_SIZE = 10485760
    # 上传文件统一使用二进制权限写入,避免Windows系统自动转换文本换行符导致文件损坏
    FILE_UPLOAD_PERMISSIONS = 0o644
    # 确认使用默认上传处理器,不要追加自定义的文本处理类上传处理器
    FILE_UPLOAD_HANDLERS = [
        'django.core.files.uploadhandler.MemoryFileUploadHandler',
        'django.core.files.uploadhandler.TemporaryFileUploadHandler',
    ]
    
  3. 排查Postman配置问题
    • 不要手动在请求头中添加Content-Type字段,让Postman自动生成带boundary分隔符的multipart请求头,手动填写的头缺少正确分隔符会导致请求体解析截断
    • 关闭Postman的请求参数自动编码开关,不要强制使用文本类编码格式处理二进制文件
    • 可直接用curl命令传文件测试,排除Postman本身的bug:
      curl -X PUT http://localhost:8000/your-upload-path \
        -H "Authorization: Bearer 你的JWT令牌" \
        -F "id_project=测试项目ID" \
        -F "Campaign_Name=测试活动名" \
        -F "ViewpointSurvey=@/本地/文件/路径/ViewpointSurvey.csv" \
        -F "ProjectSurvey=@/本地/文件/路径/ProjectSurvey.csv" \
        -F "Trajectories=@/本地/文件/路径/Trajectories.csv" \
        -F "screenshots=@/本地/文件/路径/screenshots.zip"
      
  4. 排除Windows系统环境干扰
    • 临时关闭Windows Defender或第三方杀毒软件的实时文件扫描,这类软件会锁定Django生成的临时上传文件,导致大文件未完全写入就被截断
    • 大文件测试时关闭runserver的热重载模式,避免文件写入过程中触发进程重启打断写入流程
  5. 加校验逻辑定位故障阶段
    在视图中增加文件哈希、大小校验逻辑,对比本地原文件参数,确认故障发生在传输解析阶段还是存储写入阶段:
    import hashlib
    def put(self, request):
        # 取ZIP文件做校验示例
        f = request.data['screenshots']
        file_hash = hashlib.md5()
        for chunk in f.chunks():
            file_hash.update(chunk)
        print(f"接口接收到的文件MD5:{file_hash.hexdigest()},文件大小:{f.size}")
        # 原有业务逻辑保持不变
    
    如果接口接收到的文件MD5、大小和本地原文件不一致,问题出在请求传输/解析环节;如果接收时参数一致,保存到磁盘后损坏,问题出在文件写入逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 14:54:19