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

使用@tornado.web.stream_request_body上传大文件异常求助

解决Tornado流式上传大文件后文件损坏的问题

我之前也碰到过一模一样的情况——用stream_request_body传大文件后,PDF之类的二进制文件直接打不开,大概率是文件写入不完整、分块处理不当或者资源没正确释放导致的。结合你的代码片段,我整理几个关键排查点和修复方案:

一、先把流式上传的核心逻辑补全

你的代码只提到了打开文件,但流式上传必须在data_received里逐块写入,还要在请求结束时确保文件关闭,不然很容易出现文件截断:

import os
import tornado.web

MAX_STREAMED_SIZE = 1024 * 1024 * 1024  # 1GB

@tornado.web.stream_request_body
class UploadHandler(tornado.web.RequestHandler):
    def prepare(self):
        # 设置单个请求的最大体大小
        self.request.connection.set_max_body_size(MAX_STREAMED_SIZE)
        # 确保上传目录存在,避免报错
        upload_dir = "./uploads"
        if not os.path.exists(upload_dir):
            os.makedirs(upload_dir)
        # 用二进制模式打开文件!这是二进制文件(PDF)不损坏的关键
        self.file_path = os.path.join(upload_dir, "uploaded_file.pdf")
        self.f = open(self.file_path, "wb")
        # 可选:记录已接收字节数,用于后续校验
        self.received_bytes = 0
        self.expected_bytes = int(self.request.headers.get("Content-Length", 0))

    def data_received(self, chunk):
        # 逐块写入字节流,不要做任何编码转换
        self.received_bytes += len(chunk)
        self.f.write(chunk)

    def post(self):
        # 请求完成后先校验文件完整性
        if self.expected_bytes > 0 and self.received_bytes != self.expected_bytes:
            os.remove(self.file_path)
            self.set_status(400)
            self.write({"error": "文件上传不完整,请重试"})
            return
        # 关闭文件句柄
        self.f.close()
        self.write({"status": "success", "file_path": self.file_path})

    def on_finish(self):
        # 兜底处理:即使请求异常中断,也要确保文件被关闭
        if hasattr(self, 'f') and not self.f.closed:
            self.f.close()

这里一定要注意:

  • 打开文件必须用"wb"二进制模式,用文本模式会因为编码规则破坏PDF的二进制结构,直接导致文件损坏。
  • data_received会被多次调用,每次传入的chunk是原生字节块,直接写入即可,别做任何decode之类的操作。

二、确认全局请求大小限制没拖后腿

有时候你在handler里设置了set_max_body_size,但Tornado应用的全局max_request_size如果更小,会直接截断请求,导致文件不完整。记得在应用初始化时同步设置全局限制:

app = tornado.web.Application(
    [
        (r"/upload", UploadHandler),
    ],
    max_request_size=MAX_STREAMED_SIZE  # 和handler里的限制保持一致
)

三、先拿小文件验证基础逻辑

如果大文件还是有问题,先传个几MB的PDF试试:

  • 如果小文件能正常打开,说明核心逻辑没问题,问题出在大文件的流式处理或网络中断上;
  • 如果小文件也损坏,那大概率是文件打开模式或者写入方式错了,重点检查open的参数和data_received里的写入逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:41:48