FastAPI返回S3图片文件流时接收端无内容应如何解决
问题原因
核心问题是S3客户端的异步上下文管理器生命周期和流读取生命周期不匹配:你在async with sess.create_client(...)代码块里获取到S3文件流后直接返回,return语句执行完成后异步上下文就会自动退出,S3连接也会随之提前关闭。后续FastAPI迭代StreamingResponse的流内容时,已经没有可用的S3连接拉取数据,导致接收端无法拿到完整响应。
修复方案
你可以封装一个异步生成器,把S3客户端上下文、流读取逻辑都包在生成器内部,保证所有流分块读取完成前S3连接不会被关闭,参考实现如下:
import uvicorn from fastapi import FastAPI from fastapi.responses import StreamingResponse from aiobotocore.session import get_session app = FastAPI() async def s3_file_stream(bucket: str, key: str): # S3客户端上下文放在生成器内部,流迭代完成前不会退出 sess = get_session() async with sess.create_client( 's3', endpoint_url="你的S3端点地址", aws_secret_access_key="你的SecretAccessKey", aws_access_key_id="你的AccessKeyId" ) as client: result = await client.get_object(Bucket=bucket, Key=key) # 逐块返回S3文件内容 async for chunk in result["Body"]: yield chunk @app.get("/") async def main(): return StreamingResponse( s3_file_stream(bucket="你的桶名", key="你的文件Key"), media_type="image/jpeg" ) if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8080)
如果需要避免浏览器使用分块传输、提升加载体验,你可以额外补充Content-Length响应头:
async def s3_file_stream(bucket: str, key: str): sess = get_session() async with sess.create_client( 's3', endpoint_url="你的S3端点地址", aws_secret_access_key="你的SecretAccessKey", aws_access_key_id="你的AccessKeyId" ) as client: result = await client.get_object(Bucket=bucket, Key=key) # 把文件大小存到生成器属性里,方便外部读取 s3_file_stream.content_length = result["ContentLength"] async for chunk in result["Body"]: yield chunk @app.get("/") async def main(): stream = s3_file_stream(bucket="你的桶名", key="你的文件Key") return StreamingResponse( stream, media_type="image/jpeg", headers={"Content-Length": str(stream.content_length)} )
内容的提问来源于stack exchange,提问作者Soltanat
相关产品推荐
相关产品推荐

