表单、文件和静态文件

前面主要处理 JSON 请求体。

实际项目里还会遇到:

  • 登录表单
  • 文件上传
  • 头像上传
  • 静态图片访问

FastAPI 都有内置支持。

一、接收表单数据

表单数据不是 JSON,而是 application/x-www-form-urlencodedmultipart/form-data

from typing import Annotated

from fastapi import FastAPI, Form

app = FastAPI()


@app.post("/login")
def login(
    username: Annotated[str, Form()],
    password: Annotated[str, Form()],
):
    return {"username": username}

/docs 里测试时,会看到表单输入框。

如果你不是用 fastapi[standard] 安装,表单和文件上传可能需要额外安装:

pip install python-multipart

本教程使用 pip install "fastapi[standard]",通常已经包含常用标准依赖。

二、接收单个上传文件

FastAPI 推荐用 UploadFile 处理上传文件。

from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/upload")
async def upload_file(file: Annotated[UploadFile, File()]):
    content = await file.read()
    return {
        "filename": file.filename,
        "content_type": file.content_type,
        "size": len(content),
    }

说明:

属性 / 方法含义
file.filename原始文件名
file.content_type文件类型,例如 image/png
await file.read()读取文件内容

UploadFile 适合上传文件,因为它不会一开始就把所有内容都当普通字符串处理。

三、保存上传文件

示例:把上传文件保存到 uploads 目录。

from pathlib import Path
from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()

UPLOAD_DIR = Path("uploads")
UPLOAD_DIR.mkdir(exist_ok=True)


@app.post("/upload")
async def upload_file(file: Annotated[UploadFile, File()]):
    save_path = UPLOAD_DIR / file.filename

    content = await file.read()
    save_path.write_bytes(content)

    return {
        "filename": file.filename,
        "saved_to": str(save_path),
        "size": len(content),
    }

真实项目要注意:

  • 不要完全相信用户上传的文件名。
  • 要限制文件大小。
  • 要校验文件类型。
  • 公开访问的文件要避免覆盖已有文件。

初学阶段先理解流程即可。

四、同时接收表单和文件

from typing import Annotated

from fastapi import FastAPI, File, Form, UploadFile

app = FastAPI()


@app.post("/profile")
async def update_profile(
    nickname: Annotated[str, Form()],
    avatar: Annotated[UploadFile, File()],
):
    content = await avatar.read()
    return {
        "nickname": nickname,
        "avatar_filename": avatar.filename,
        "avatar_size": len(content),
    }

这种接口的请求类型是 multipart/form-data

五、挂载静态文件

如果你想让浏览器直接访问某个目录里的文件,可以使用 StaticFiles

目录结构:

fastapi-demo/
├── main.py
└── static/
    └── hello.txt

main.py

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

app = FastAPI()

app.mount("/static", StaticFiles(directory="static"), name="static")

访问:

http://127.0.0.1:8000/static/hello.txt

就能看到 static/hello.txt 的内容。

六、API 和静态文件的区别

类型示例作用
API 接口/users/1返回动态数据,通常是 JSON
静态文件/static/logo.png返回文件内容,例如图片、CSS、文本

后台接口项目通常只需要少量静态文件。复杂前端项目一般由 Vite、Next.js、Nginx 或对象存储来处理静态资源。