Skip to content

18. FastAPI 响应类型_文件格式 ​

文件响应与 JSON 响应的区别 ​

下载接口发送文件字节,而不是把文件内容包装成 JSON。FileResponse 适合已有磁盘文件;StreamingResponse 适合运行时逐块生成的数据。二者都应明确文件类型和下载文件名。

使用 ID 映射文件,避免外部路径直通磁盘 ​

python
from pathlib import Path
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse

app = FastAPI()
BASE = Path(__file__).resolve().parent / "downloads"
BASE.mkdir(exist_ok=True)
(BASE / "guide.txt").write_text("你好,文件下载!\n", encoding="utf-8")
FILES = {"guide": {"path": BASE / "guide.txt", "name": "学习指南.txt"}}

@app.get("/files/{file_id}")
def download(file_id: str):
    meta = FILES.get(file_id)
    if meta is None or not meta["path"].is_file():
        raise HTTPException(404, "文件不存在")
    return FileResponse(path=meta["path"], filename=meta["name"],
                        media_type="text/plain; charset=utf-8")

保存为 main.py 并启动。访问 /files/guide 应下载文本文件;/files/unknown 返回 404。演示为便于复现会在启动时写入示例文件,实际业务应由上传或生成流程创建文件。

下载行为由什么决定 ​

Content-Type 表示内容种类;Content-Disposition 表示附件下载或浏览器内联展示;filename 决定建议保存名称。FileResponse 能设置文件相关响应头,具体 Range 支持和缓存行为应以安装的 Starlette 版本为准。

使用 curl.exe -D headers.txt -o guide.txt http://127.0.0.1:8000/files/guide 可分别检查响应头和下载结果。PDF 常用 application/pdf;未知二进制常用 application/octet-stream。

临时生成文件的生命周期 ​

不要在 with TemporaryDirectory() 退出后返回里面的文件路径,因为真正发送时文件可能已经删除。需要把清理安排到文件发送完成之后,例如通过响应的后台清理任务,或使用定期清理的缓存目录。

生成 CSV 时要正确处理逗号、换行、引号和编码,可使用标准库 csv,不要手工拼接分隔符。若供电子表格打开,还需根据业务处理以公式字符开头的不可信单元格内容。

进一步的工程处理 ​

文件 ID 不等于访问授权;先检查当前用户能否下载,再返回文件。不要接受 ?path=C:/... 直接读取服务器文件。对象存储可使用短时授权链接,海量下载可交给专门的文件服务。受保护文件的缓存策略应避免共享缓存泄露。

练习:增加 PDF 文件映射;测试不存在的 ID 和实际文件被删除两种情况。比较浏览器下载和 curl.exe -i 的响应头。