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

如何使用FastAPI的request.stream()将文件分块上传至Google Cloud Storage?

如何使用FastAPI的request.stream()将文件分块上传至Google Cloud Storage?

我完全懂你现在的困境——FastAPI的request.stream()返回的是异步生成器,但gcloud.aio.storage的上传接口根本不认这个类型,它只接受字节、字符串或者基于io.IOBase的类文件对象,而且因为是异步客户端,这个类文件对象还得支持异步读取才行。

咱们可以自己写一个简单的包装类,把FastAPI请求的异步生成器转换成符合要求的异步类文件对象。这样就能实现边读请求体边上传到GCS,完全不用把整个大文件加载到内存里。

首先定义这个包装类:

import io
from typing import AsyncGenerator

class AsyncRequestStream(io.IOBase):
    def __init__(self, stream: AsyncGenerator[bytes, None]):
        self.stream = stream
        self.buffer = b""

    async def read(self, n: int = -1) -> bytes:
        # 先返回缓冲区里剩余的数据
        if self.buffer and n != 0:
            if n == -1 or len(self.buffer) <= n:
                data = self.buffer
                self.buffer = b""
                return data
            else:
                data = self.buffer[:n]
                self.buffer = self.buffer[n:]
                return data
        
        # 从请求的异步生成器里读取下一块数据
        try:
            chunk = await anext(self.stream)
        except StopAsyncIteration:
            return b""
        
        if n == -1:
            return chunk
        
        # 如果读取的块比需要的大,把多余的部分存进缓冲区
        if len(chunk) > n:
            self.buffer = chunk[n:]
            return chunk[:n]
        return chunk

然后修改你的上传函数,把请求流包装成这个类的实例再传给GCS客户端:

from fastapi import Request
import gcloud.aio.storage

async def upload(request: Request, storage_client: gcloud.aio.storage.Storage):
    # 包装request的异步生成器
    upload_stream = AsyncRequestStream(request.stream())
    
    # 最好带上Content-Length,让GCS提前知道文件大小(如果请求里有的话)
    content_length = request.headers.get("Content-Length")
    upload_kwargs = {}
    if content_length:
        upload_kwargs["content_length"] = int(content_length)
    
    await storage_client.upload(
        "my_bucket",
        "my_object",
        upload_stream,
        **upload_kwargs
    )

这个包装类的工作逻辑很简单:它维护了一个小缓冲区,每次调用read()时,先返回缓冲区里剩下的数据;如果缓冲区空了,就从请求的异步生成器里读取下一块数据,按需切割后返回,多余的部分留到下一次读取。这样就完美适配了gcloud.aio.storage对异步类文件对象的要求,全程都是流式处理,内存占用特别低,完全适合处理超大文件上传。

备注:内容来源于stack exchange,提问作者ChrisC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 14:03:08