首页
/ FastAPI 接收客户端上传文件实战:File、UploadFile 与 multipart/form-data 机制

FastAPI 接收客户端上传文件实战:File、UploadFile 与 multipart/form-data 机制

2026-09-06 12:54:56作者:钟日瑜

本文基于 FastAPI 官方教程「Request 中的文件」,系统讲解如何在 FastAPI 接口中声明并处理客户端上传的文件:从安装 python-multipart 前置依赖,到用 bytesUploadFile 两种方式接收文件、声明可选上传与多文件批量上传,并结合 fastapi/params.pyfastapi/datastructures.py 的源码,剖析 File 参数继承体系与 UploadFile 的底层实现。读完本文,你将掌握 FastAPI 文件上传接口的完整写法,并理解其背后的 HTTP 表单编码机制与线程池执行细节。

一、前置条件:安装 python-multipart

要接收客户端上传的文件,必须先安装 python-multipart 包。将其加入项目:

$ uv add python-multipart

之所以有这个依赖,是因为上传的文件会以**表单数据(form data)**的方式随请求发送,而 FastAPI 需要 python-multipart 来解析 multipart/form-data 编码的请求体。

二、导入 File 并定义文件参数

fastapi 导入 FileUploadFile,然后像使用 BodyForm 一样声明文件参数。以下代码来自仓库中的可运行示例 tutorial001_an_py310.py

from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: Annotated[bytes, File()]):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    return {"filename": file.filename}

两点关键说明:

  1. File 的继承关系File 是一个直接继承自 Form 的类。这一点可以在源码中得到印证:fastapi/params.py 中定义了 class Form(Body),随后在 fastapi/params.py 定义了 class File(Form),并且 File 将默认 media_type 固定为 "multipart/form-data"(见 fastapi/params.py)。
  2. 导入的是"函数"而非"类":当从 fastapi 导入 QueryPathFile 等名称时,它们实际上是返回对应参数类(最终都派生自 Pydantic 的 FieldInfo)的函数,Annotated[bytes, File()] 这种写法正是利用函数调用结果携带参数元信息。

提示:声明文件参数时必须使用 File。因为如果不用 File,该参数会被 FastAPI 解释为 Query 参数或 Body(JSON)参数,而不是表单中的文件字段。

当参数类型声明为 bytes 时,FastAPI 会自动读取上传的文件,并把文件内容以 bytes 的形式传给你。需要注意的是,这意味着整个文件内容都会驻留在内存中——对较小的文件这完全没问题,但很多场景下使用 UploadFile 会更合适。

三、使用 UploadFile 声明文件参数

在上面的示例中,/uploadfile/ 路由直接以 UploadFile 作为参数类型。相比 bytes,使用 UploadFile 有以下优点:

  • 参数不需要使用 File() 作为默认值;
  • 底层使用"spooled(池化/暂存)"文件:文件先保存在内存中,当超过一定大小上限后自动转存到磁盘;
  • 因此对图片、视频、大型二进制文件等大文件也能良好工作,不会耗尽内存;
  • 可以读取上传文件的元数据;
  • 提供文件类似(file-like)的 async 接口;
  • 它暴露了一个真实的 Python SpooledTemporaryFile 对象,可以直接传给其他期望接收"文件类对象"的库。

3.1 UploadFile 的属性

UploadFile 提供以下属性:

  • filenamestr,上传文件的原始名称(例如 myimage.jpg);
  • content_typestr,内容类型(MIME 类型 / 媒体类型,例如 image/jpeg);
  • fileSpooledTemporaryFile(文件类对象)。这是真正的 Python 文件对象,可以直接传给期望接收文件类对象的其他函数或库。

从源码 fastapi/datastructures.py 还可以看到,FastAPI 的 UploadFile 在 Starlette 基础上还标注了 size(文件字节大小)和 headers(请求头)等属性,且每个属性都带有 Doc 注解,会被文档工具用于生成说明。

3.2 UploadFile 的 async 方法

UploadFile 提供以下 async 方法,它们全部是对底层文件对象(内部为 SpooledTemporaryFile)对应方法的封装(见 fastapi/datastructures.py):

  • write(data):将 databytes)写入文件;
  • read(size):从文件读取 sizeint)个字节,默认 size=-1 表示读取到结尾;
  • seek(offset):定位到文件的字节位置 offsetint)。例如 await myfile.seek(0) 会回到文件开头——当你执行过一次 await myfile.read() 之后需要再次读取内容时,这一步尤其有用;
  • close():关闭文件。

由于这些都是 async 方法,调用时必须使用 await。例如在 async 路径操作函数中读取内容:

contents = await myfile.read()

而如果你在一个普通的 def(同步)路径操作函数中,可以直接访问 UploadFile.file,例如:

contents = myfile.file.read()

技术细节(async):使用这些 async 方法时,FastAPI 会在线程池(threadpool)中执行底层的文件操作并等待其完成,从而避免阻塞事件循环。

技术细节(Starlette):FastAPI 的 UploadFile 直接继承自 Starlette 的 UploadFile,并补充了若干部件使其兼容 Pydantic 和 FastAPI 的其他部分。源码 fastapi/datastructures.py 中的 __get_pydantic_json_schema__ 方法返回 {"type": "string", "contentMediaType": "application/octet-stream"},这使得 OpenAPI 文档中上传文件字段被描述为二进制字符串;_validate 类方法则负责在 Pydantic 校验时确保传入的确实是 UploadFile 实例。

四、什么是"表单数据"

HTML 表单(<form></form>)向服务器发送数据的方式通常采用一种"特殊的"编码,与 JSON 不同。FastAPI 会确保从正确的位置读取这些数据,而不是去解析 JSON

技术细节:表单数据如果不包含文件,通常以媒体类型 application/x-www-form-urlencoded 编码;但如果表单包含文件,则会以 multipart/form-data 编码。当你使用 File 时,FastAPI 便知道必须从请求体的正确部分(而非 JSON)获取文件。这一点与源码中三类参数的默认 media_type 一一对应:Body 默认为 application/jsonfastapi/params.py)、Form 默认为 application/x-www-form-urlencodedfastapi/params.py)、File 默认为 multipart/form-datafastapi/params.py)。

警告:你可以在一个路径操作中同时声明多个 FileForm 参数,但不能同时声明期望 JSON 的 Body 字段——因为请求体将以 multipart/form-data 而非 application/json 编码。这不是 FastAPI 的限制,而是 HTTP 协议本身的约束。

五、可选的文件上传

通过标准类型标注并设置默认值 None,可以让文件变为可选。示例见 tutorial001_02_an_py310.py

from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: Annotated[bytes | None, File()] = None):
    if not file:
        return {"message": "No file sent"}
    else:
        return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile | None = None):
    if not file:
        return {"message": "No upload file sent"}
    else:
        return {"filename": file.filename}

bytes 类型使用 Annotated[bytes | None, File()] = None,对 UploadFile 类型直接写 UploadFile | None = None 即可,客户端未上传文件时参数取值为 None

六、为 UploadFile 附加额外元数据

你同样可以在 UploadFile 上使用 File(),例如为上传字段附加描述等元数据。示例见 tutorial001_03_an_py310.py

from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: Annotated[bytes, File(description="A file read as bytes")]):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(
    file: Annotated[UploadFile, File(description="A file read as UploadFile")],
):
    return {"filename": file.filename}

File() 接受 descriptionaliasexamples 等参数,这些元数据会体现在自动生成的 OpenAPI 文档中,便于前端在 Swagger UI 中理解该文件字段。

七、多文件上传

可以同时上传多个文件,它们会被映射到同一个以表单数据发送的"表单字段"。做法是声明一个 bytesUploadFile 的列表。示例见 tutorial002_an_py310.py,其中还包含一个可直接用于浏览器测试的 HTML 表单页面:

from typing import Annotated

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse

app = FastAPI()


@app.post("/files/")
async def create_files(files: Annotated[list[bytes], File()]):
    return {"file_sizes": [len(file) for file in files]}


@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile]):
    return {"filenames": [file.filename for file in files]}


@app.get("/")
async def main():
    content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
    """
    return HTMLResponse(content=content)

你将按照声明的类型,得到一个 bytesUploadFilelist

技术细节:也可以从 starlette.responses 导入 HTMLResponseFastAPI 为了方便开发者,同样通过 fastapi.responses 提供这些 starlette.responses 中的响应类;但其中大多数响应类直接来自 Starlette。

7.1 多文件上传并附加额外元数据

与前面一样,你也可以在 UploadFile 上使用 File() 设置额外参数。示例见 tutorial003_an_py310.py

@app.post("/files/")
async def create_files(
    files: Annotated[list[bytes], File(description="Multiple files as bytes")],
):
    return {"file_sizes": [len(file) for file in files]}


@app.post("/uploadfiles/")
async def create_upload_files(
    files: Annotated[
        list[UploadFile], File(description="Multiple files as UploadFile")
    ],
):
    return {"filenames": [file.filename for file in files]}

八、小结

使用 FilebytesUploadFile 这三个要素,即可在 FastAPI 中声明以表单数据(multipart/form-data)方式发送的可上传文件:

  • 小文件、只需字节流:声明为 Annotated[bytes, File()],FastAPI 自动读入内存;
  • 大文件、需要元数据:使用 UploadFile,获得内存/磁盘自动暂存、文件名与内容类型元数据、可复用的文件对象;
  • 可选上传:类型加 | None 并给默认值 None
  • 多文件上传:声明 list[bytes]list[UploadFile]
  • 附加约束与说明:通过 File(description=..., alias=...) 等参数补充元数据,自动进入 OpenAPI 文档。

更多示例可参考 docs_src/request_files/ 目录下的完整可运行代码,以及对应的英文原版教程页面;核心实现见 fastapi/params.pyForm/File 参数类)与 fastapi/datastructures.pyUploadFile 类)。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388