Skip to content

JSON 之外: 表单数据与文件上传

虽然 JSON 是现代 API 的标准,但有时您需要与传统的 HTML 表单交互或处理文件上传。FastAPI 能够优雅地处理这些非 JSON 请求,但这需要一种特定的方法。

为了处理上传文件和表单数据,FastAPI 依赖于一个名为 python-multipart 的外部库。在继续之前,您必须安装它:

Terminal window
pip install python-multipart

当从 HTML <form> 接收数据时,媒体类型通常是 application/x-www-form-urlencoded。这与 JSON 不同。要告诉 FastAPI 从表单数据而不是 JSON 中读取,请使用 Form 类。

from typing import Annotated
from fastapi import FastAPI, Form
app = FastAPI()
@app.post("/login/")
async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):
return {"username": username}

这与 Body、Query 或 Path 的工作方式完全相同。它告诉 FastAPI 在表单数据中查找 username 和 password 字段。

FastAPI 提供了两种定义文件参数的方式:bytes (使用 File) 和 UploadFile。

如果您将类型声明为 bytes,FastAPI 将把整个文件读入内存。

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

这对于小文件来说很简单,但对于大文件(如视频)来说,它可能会耗尽您服务器的所有内存并导致应用程序崩溃。

使用 UploadFile 更安全、功能更丰富。它使用了 Python 的 SpooledTemporaryFile。这意味着它会在内存中保留到达到一定大小限制,然后自动溢出到磁盘。

from fastapi import UploadFile
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename, "content_type": file.content_type}

两种方法的比较:

特性bytesUploadFile
存储完全存储在 RAM 中缓冲池(RAM + 磁盘)
性能对小文件快速对大文件高效
元数据无(仅原始数据)包含文件名、内容类型
接口Python bytes 对象类文件对象(读/写/关闭)

通过声明一个 UploadFile 列表,您可以一次处理多个文件。

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

此端点将接受发送多个文件(例如 <input type="file" multiple>)的 HTML 表单并高效地处理它们。