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

如何使用Sanic流式生成并下载超大Zip文件?

解决Sanic流式生成大压缩包中断问题

修复流式响应的发送逻辑

你的代码中断的核心原因很可能是没有正确标记响应块的结束状态,导致客户端一直在等待后续数据,最终超时断开。Sanic的response.send()方法默认会把more_body设为False,意味着当前是最后一块数据;但你循环发送所有chunk时都用了默认值,会让客户端提前认为传输结束,或者后续等待超时。

正确的做法是给除了最后一块之外的所有chunk标记more_body=True,最后一块不标记(或设为False):

import os
from zipstream import ZipStream

async def download_zip(request, dataset_id, file_path):
    zs = ZipStream(chunk_size=1024*1024)  # 调整为1MB块大小,减少发送次数
    for root, _, files in os.walk(file_path):
        for file in files:
            fpath = str(os.path.join(root, file))
            zs.add_path(fpath)

    response = await request.respond(
        headers={'Content-Disposition': f'attachment; filename="{dataset_id}.zip"'},
        content_type='application/zip'
    )

    chunk_iter = iter(zs)
    # 处理第一个chunk
    prev_chunk = next(chunk_iter, None)
    if not prev_chunk:
        await response.send(b'')
        return
    
    # 发送中间chunk,标记more_body=True
    for chunk in chunk_iter:
        await response.send(prev_chunk, more_body=True)
        prev_chunk = chunk
    
    # 发送最后一个chunk,不标记more_body(默认False)
    await response.send(prev_chunk)

调整Sanic超时配置

传输10GB大文件需要更长的连接时间,Sanic默认的超时设置可能会主动断开连接。在你的Sanic应用配置中调大相关超时参数:

app = Sanic("MyApp")
# 设置1小时超时(根据实际需求调整)
app.config.RESPONSE_TIMEOUT = 3600
app.config.REQUEST_TIMEOUT = 3600

关于模拟文件适配file_stream的方案

file_stream()本质是基于真实文件路径实现的异步流式传输,无法直接适配ZipStream的动态生成场景。如果一定要复用类似逻辑,你可以自定义一个异步类文件对象,将ZipStream的chunk输出封装为read()方法,但这种方式并没有比修复流式响应更简单,反而增加复杂度,不推荐。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 21:03:15