如何通过FastAPI下载大文件?解决UnicodeDecodeError编码错误
FastAPI返回大.tar.gz文件时UnicodeDecodeError问题解决
问题背景
需要从FastAPI后端下载大.tar.gz文件,服务端验证文件路径后使用Starlette的FileResponse返回文件,代码如下:
return FileResponse(path=file_name, media_type='application/octet-stream', filename=file_name)
触发的错误
执行时抛出UnicodeDecodeError,错误栈信息:
File "/usr/local/lib/python3.10/dist-packages/fastapi/routing.py", line 149, in serialize_response return jsonable_encoder(response_content) File "/usr/local/lib/python3.10/dist-packages/fastapi/encoders.py", line 130, in jsonable_encoder return ENCODERS_BY_TYPE[type(obj)](obj) File "pydantic/json.py", line 52, in pydantic.json.lambda UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte
尝试改用StreamingResponse
切换为StreamingResponse实现流式返回,代码如下,但仍触发相同错误:
@x.post("/download") async def download(file_name=Body(), token: str | None = Header(default=None)): file_name = file_name["file_name"] # 文件格式类似xx.tar def iterfile(): with open(file_name,"rb") as f: yield from f return StreamingResponse(iterfile(),media_type='application/octet-stream')
根因定位
经排查,错误并非出自下载API,而是转发该请求的API。转发代码如下:
@("/") def f(): req = requests.post(url ="/download") return req.content
直接返回req.content(二进制字节流)时,FastAPI会默认调用jsonable_encoder尝试将其序列化为JSON,而二进制压缩文件的字节无法被UTF-8解码,因此触发编码错误。
解决办法
在转发请求的API中,返回时显式指定media_type为application/octet-stream,确保FastAPI将响应识别为二进制流而非JSON。修改后的转发代码示例:
from fastapi import Response @("/") def f(): req = requests.post(url ="/download") return Response(content=req.content, media_type='application/octet-stream')
通过指定正确的媒体类型,FastAPI会直接返回二进制内容,不再尝试JSON序列化,编码错误问题得以解决。
内容的提问来源于stack exchange,提问作者Yuqi Wang
相关产品推荐
相关产品推荐

