Quick Reference 速查:FastAPI 备忘清单实战指南——从参数校验、依赖注入到 Token 认证
2026/9/14 18:50:47 网站建设 项目流程

Quick Reference 速查:FastAPI 备忘清单实战指南——从参数校验、依赖注入到 Token 认证

【免费下载链接】reference面向开发者的技术速查清单(Cheat Sheets)集合,整理常见技术、工具与开发流程,帮助快速查阅关键信息,提高开发效率。项目地址: https://gitcode.com/GitHub_Trending/referen/reference

本文为 Quick Reference 技术速查仓库中 FastAPI 备忘清单 的深度扩写版本,覆盖安装运行、路径/查询参数与校验、请求体、表单与文件上传、依赖项体系以及基于 Token 的认证与 HTTPS 配置等全部核心内容,并补充了各参数取值、依赖缓存机制与运行前提的说明。读完后你可以直接复制其中的代码片段,搭建一个带参数校验、依赖注入和 Token 认证的 FastAPI 应用。

这份速查清单在仓库中的位置

本仓库是一份面向中文开发者的技术速查清单(Cheat Sheets)集合,各主题以docs/目录下的 Markdown 文件形式维护,README.md首页通过卡片链接聚合所有速查表。FastAPI 属于 Python 技术栈条目,同时出现在首页「正在建设中...」与「Python」两个分区中(见 README.md 中指向docs/fastapi.md的链接)。

与 Python 生态相关的速查表还包括 Python 备忘清单、pip、uv 等,FastAPI 的类型提示、切片操作等基础语法可以回溯到 Python 清单查阅。

适用环境说明:原文档标注的验证环境为 Python3.9.5与 FastAPI0.103.1,因此文档中Union[str, None]的写法是面向 3.9 及更早版本保守书写的;在 Python 3.10+ 中可等价使用str | None(文档「声明元数据」一节即混用了str | None新式写法)。

入门:安装、运行与最小程序

安装 FastAPI

完整开发环境一次装齐(包含uvicornpython-multipart等可选依赖):

$ pip install "fastapi[all]"

生产部署时推荐分开安装,避免带入开发期依赖:

$ pip install fastapi $ pip install "uvicorn[standard]"

启动服务器

FastAPI 本身不内置 HTTP 服务器,通过 ASGI 服务器uvicorn运行:

$ uvicorn main:app --reload

main:app的含义是「在main模块中找到名为app的应用对象」,--reload表示代码变更后自动重载进程,适合开发期使用。

最小程序

下面代码会直接启动 http 服务,也可以使用uvicorn main:app --reload

from fastapi import FastAPI import uvicorn app = FastAPI() # http://127.0.0.1:8000/ @app.get("/") async def root(): return {"message": "Hello World"} if __name__ == '__main__': uvicorn.run(app='main:app', reload=True)

说明:

  • 路由函数用async def声明,FastAPI 会将其识别为异步处理函数,适合 IO 密集型场景(数据库、HTTP 下游调用);
  • 函数返回的dict会被 FastAPI 序列化为 JSON 响应;
  • 原文档中uvicorn.run(app='main:app', reload=True)的写法里appuvicorn.run的第一个位置参数,传字符串时会被当作「模块路径:对象名」解析。更规范的等价写法是uvicorn.run("main:app", reload=True),或者直接通过命令行uvicorn main:app --reload启动。

路径参数:URL 中的动态片段

最基本的路径参数

# http://127.0.0.1:8000/items/1 @app.get("/items/{item_id}") async def read_item(item_id): return {"item_id": item_id} # item_id自定义

路径中{item_id}占位符的取值会按同名参数注入函数,item_id这个名字可以自定义。

多个路径参数

# http://127.0.0.1:8000/items/1/2 @app.get("/items/{item_id}/{user_id}") async def read_item(item_id, user_id): return {"item_id": item_id, "user_id": user_id}

有类型的路径参数

# http://127.0.0.1:8000/items/1 @app.get("/items/{item_id}") async def read_item(item_id: int): return {"item_id": item_id}

声明item_id: int后,FastAPI 基于标准 Python 类型提示做自动转换与校验:访问/items/abc会得到 422 校验错误,而不是把字符串带进业务逻辑。这是 FastAPI「类型提示即接口契约」的核心机制。

文件路径参数

路径片段默认不含斜杠/,若参数本身是带/的文件路径,需要在占位符上声明:path格式:

# http://127.0.0.1:8000/file//home/my/my.txt @app.get("/file/{file_path:path}") async def read_item(file_path): return {"file_path": file_path}

查询参数:URL 中的键值对

带默认值的查询参数

函数参数带默认值即被视为查询参数:

# http://127.0.0.1:8000/items/?skip=0&limit=2 fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}] @app.get("/items/") async def read_item(skip: int = 0, limit: int = 10): return fake_items_db[skip: skip + limit]

可选查询参数

# http://127.0.0.1:8000/items/1?q=admin from typing import Union @app.get("/items/{item_id}") async def read_item(item_id: str, q: Union[str, None] = None): if q: return {"item_id": item_id, "q": q} return {"item_id": item_id}

多路径多查询参数

路径参数与查询参数可以在同一接口中混用:

# http://127.0.0.1:8000/users/1/items/2 # or # http://127.0.0.1:8000/users/1/items/2?q=query&short=true @app.get("/users/{user_id}/items/{item_id}") async def read_user_item( user_id: int, item_id: str, q: Union[str, None] = None, short: bool = False ): item = {"item_id": item_id, "owner_id": user_id} if q: item.update({"q": q}) if not short: item.update( {"description": "这是一个令人惊叹的项目,有很长的描述"} ) return item

注意short: bool = False:查询参数short=true/short=false会被自动转换为 Python 布尔值。

必需查询参数

无默认值的参数即为必需参数,请求中缺失时返回 422 错误:

# http://127.0.0.1:8000/items/123?needy=yes @app.get("/items/{item_id}") async def read_user_item(item_id: str, needy: str): item = {"item_id": item_id, "needy": needy} return item

请求体:用 Pydantic 模型描述入参

当接口接收 JSON 请求体时,用 PydanticBaseModel定义结构,字段默认值、可选性都由模型声明:

from pydantic import BaseModel from typing import Union class Item(BaseModel): name: str = '小明' description: Union[str, None] = None price: float tax: Union[float, None] = None @app.post("/items/") async def create_item(item: Item): print(item.name) return item

字段语义:name有默认值'小明'(可省略);descriptiontax为可选字段;price无默认值,是必填字段且必须是可解析为float的值。

curl调用该接口:

curl -X 'POST' \ 'http://127.0.0.1:8000/items/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "name": "小明", "description": "string", "price": 0, "tax": 0 }'

查询参数与字符串校验

当参数需要额外约束(长度、正则等)时,用Query显式声明元数据:

from fastapi import Query @app.get("/items/") async def read_items( q: Union[str, None] = Query(default=None, max_length=50) ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) return results

Query常用参数一览:

参数含义类型
default默认值任意类型
max_length最大长度int
min_length最小长度int
pattern正则匹配string
alias别名参数(URL 中实际使用的键名)string
deprecated标记为准备弃用的参数bool

多个相同的查询参数

URL 中出现多个同名的键值对(如?q=foo&q=bar),声明列表类型即可收集为list

# http://127.0.0.1:8000/items/?q=foo&q=bar @app.get("/items/") async def read_items( q: Union[List[str], None] = Query(default=None) ): query_items = {"q": q} return query_items

路径参数与数值校验

Path的用法与Query基本相同(可参考 FastAPI 官方文档中 path-params-numeric-validations 章节),区别是约束作用于路径占位符而非查询键。使用新版写法时,用Annotated把元数据与类型注解分离,可读性更好:

from fastapi import FastAPI, Path, Query from typing_extensions import Annotated @app.get("/items/{item_id}") async def read_items( item_id: Annotated[int, Path(title="要获取的项目的 ID")], q: Annotated[str | None, Query(alias="item-query")] = None, ): results = {"item_id": item_id} if q: results.update({"q": q}) return results

这个例子同时演示了两件事:路径参数item_id通过Path(title=...)在自动生成的 API 文档中展示友好标题;查询参数q通过Query(alias="item-query")改变 URL 中的键名,函数内仍用q接收。

Path常用参数一览(数值约束用于int/float类型参数):

参数含义类型
...(与Query相同的参数,如defaulttitlealiasdescription等)Query具有一致的元数据能力...
ge大于等于int/float
gt大于int/float
le小于等于int/float
lt小于int/float
titleAPI 文档中展示的标题string

注:原文档此处参数表中le出现两次、缺少「小于」一行,上表已按ge/gt/le/lt四个完整的数值比较约束整理。

其他参数:Cookie 与 Header

CookieHeader参数都具有Query的校验参数能力(max_lengthmin_length等),下面示例展示了如何用Annotated语法声明它们。

Cookie 参数

from fastapi import Cookie @app.get("/items/") async def read_items( ads_id: Annotated[Union[str, None], Cookie()] = None ): return {"ads_id": ads_id}

请求携带 Cookieads_id=xxx时即可取值,缺失时为None

Header 参数

from fastapi import Header @app.get("/items/") async def read_items( user_agent: Annotated[Union[str, None], Header()] = None, items_id: Annotated[Union[int, None], Header(ge=1)] = None ): return {"User-Agent": user_agent, "items_id": items_id}

两点说明:

  • Header()默认会将请求头名中的下划线映射为连字符,即user_agent对应请求头User-Agent
  • Header(ge=1)演示了 Header 参数同样支持数值校验约束,这里保证items-id头取值不小于 1。

表单数据:Form 接收表单字段

当接口接收的不是 JSON,而是application/x-www-form-urlencoded表单字段时,要使用Form

安装依赖

$ pip install python-multipart

前端 HTML 表单

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <form method="post" action="http://127.0.0.1:8000/login"> <span>账号:</span><input type="text" name="username"> <br> <span>密码:</span><input type="password" name="password"> <br> <input type="submit" value="登录"> </form> </body> </html>

表单字段名name="username"与后端Form参数名一一对应。

后端 FastAPI 接收

from fastapi import FastAPI, Form import uvicorn app = FastAPI() @app.post("/login/") async def login(username: str = Form(), password: str = Form()): return {"username": username} if __name__ == '__main__': uvicorn.run(app='main:app', reload=True)

username: str = Form()Form()作为默认值传入,表示该参数从表单字段解析,且为必填(无业务默认值)。

文件上传:UploadFile

文件上传走multipart/form-data协议,参数类型声明为UploadFile(同样需要安装python-multipart):

from fastapi import FastAPI, UploadFile from fastapi.responses import HTMLResponse @app.post("/uploadfile/") async def create_upload_file(file: UploadFile): print(file.file.read().decode()) return {"filenames": file.filename, "type": str(type(file.file))} @app.get("/") async def main(): content = """<body> <form action="/uploadfile/" enctype="multipart/form-data" method="post"> <input name="file" type="file" multiple> <input type="submit"> </form> </body>""" return HTMLResponse(content=content)

首页返回一个带enctype="multipart/form-data"的上传表单,提交后进入create_upload_file;示例中直接读取文件字节内容并打印,同时返回上传文件名与底层文件对象的类型。

UploadFile 属性

属性名含义返回
filename文件名上传的文件名
content_type内容类型MIME类型
file文件SpooledTemporaryFile,具有readwrite方法

UploadFile async 方法

方法名含义
write(data)data写入文件
read(size)按指定数量的字节读取文件内容
seek(offset)移动至文件offsetint)字节处的位置
close()关闭文件

SpooledTemporaryFile是内存/磁盘混合的临时文件实现:小文件在内存中操作,超过阈值后自动落盘,因此大文件上传不会撑爆内存;在async上下文中调用read等方法时,FastAPI 会将其放到线程池执行,避免阻塞事件循环。

依赖项:把重复逻辑抽成可注入单元

依赖项使用场景

  • 共享业务逻辑(复用相同的代码逻辑)
  • 共享数据库连接
  • 实现安全、验证、角色权限
  • 等……

创建依赖项

from typing import Union from fastapi import Depends, FastAPI app = FastAPI()

read_itemsread_users方法依赖common_parameters,白话就是这两个接口都需要qskiplimit三个查询参数:

async def common_parameters( q: Union[str, None] = None, skip: int = 0, limit: int = 100 ): return {"q": q, "skip": skip, "limit": limit} @app.get("/items/") async def read_items( commons: dict = Depends(common_parameters) ): return commons @app.get("/users/") async def read_users( commons: dict = Depends(common_parameters) ): return commons

执行流程:请求进入/items//users/时,FastAPI 先解析q/skip/limit并调用common_parameters,把其返回值注入路由函数的commons参数。后续给依赖加上鉴权、数据库会话等逻辑,所有使用它的接口自动生效。

类作为依赖项

依赖不必是函数,类也可以——FastAPI 会把路由函数的查询参数传给类的构造器:

from typing import Union from fastapi import Depends, FastAPI app = FastAPI() fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}] class CommonQueryParams: def __init__( self, q: Union[str, None] = None, skip: int = 0, limit: int = 100 ): self.q = q self.skip = skip self.limit = limit

read_items接收一个commons参数,类型是CommonQueryParamsCommonQueryParams接收的三个参数,是调用 API 时从 URL 传入的:

@app.get("/items/") async def read_items( commons: CommonQueryParams = Depends(CommonQueryParams) ): response = {} if commons.q: response.update({"q": commons.q}) items = fake_items_db[commons.skip : commons.skip + commons.limit] response.update({"items": items}) return response

还可以简写:当参数类型本身就是依赖类时,Depends()不带参数也可以,FastAPI 会自动使用该类型作为依赖:

@app.get("/items/") async def read_items( # 这里的 Depends 没有传参,FastAPI 会自动使用 CommonQueryParams commons: CommonQueryParams = Depends() ): response = {} if commons.q: response.update({"q": commons.q}) items = fake_items_db[commons.skip : commons.skip + commons.limit] response.update({"items": items}) return response

类作为依赖的优势:多参数聚合为对象、支持方法链式调用(commons.xxx),比一长串平铺参数更易维护。

子依赖项:依赖可以嵌套

依赖项可以依赖其他依赖项,只要不晕,可以无数次套娃:

from typing import Union from fastapi import Cookie, Depends, FastAPI app = FastAPI() def query_extractor(q: Union[str, None] = None): return q def query_or_cookie_extractor( q: str = Depends(query_extractor), last_query: Union[str, None] = Cookie(default=None), ): if not q: return last_query return q # read_query函数依赖query_or_cookie_extractor函数 # query_or_cookie_extractor函数又依赖query_extractor函数 # 就是说依赖项可以依赖其他依赖项,只要你不晕,可以无数次套娃 @app.get("/items/") async def read_query( query_or_default: str = Depends(query_or_cookie_extractor) ): return {"q_or_cookie": query_or_default}

这段代码实现了一个典型的多来源取值策略:优先取查询参数q,查询参数缺失时回退到 Cookielast_query。调用链为read_query -> query_or_cookie_extractor -> query_extractor,每一层都只关心自己的职责,便于单独测试。

不使用缓存(use_cache=False)

同一请求中,相同依赖默认只执行一次,其余引用共享同一结果(缓存)。使用use_cache = False参数可让每次Depends引用都重新执行——不用它的话,valuevalue1是一样的:

def result_value(): value = randint(1, 99) return value def get_value( value: int = Depends(result_value, use_cache=False), value1: int = Depends(result_value, use_cache=False) ): return value, value1 @app.get('/value/') async def needy_dependency(value: tuple = Depends(get_value)): return {"value": value}

从源码结构看,这是 FastAPI 依赖求解机制中的一个开关:请求处理时 FastAPI 构建依赖图并按节点求解,默认以「节点」为单位缓存结果;use_cache=False则强制每个引用点独立求解。典型用途是需要独立随机数、独立数据库会话(如两个并行的读写会话)等场景。

全局依赖项

在创建FastAPI实例时通过dependencies参数注册的依赖,会作用于应用内所有路由:

from fastapi import Depends, FastAPI, Header, HTTPException async def verify_token(x_token: str = Header()): if x_token != "fake-super-secret-token": raise HTTPException(status_code=400, detail="X-Token 标头无效") async def verify_key(x_key: str = Header()): if x_key != "fake-super-secret-key": raise HTTPException(status_code=400, detail="X-Key 标头无效") return x_key

全局依赖项很有用,后面的安全性就可以使用全局依赖项:

app = FastAPI( dependencies=[Depends(verify_token), Depends(verify_key)] ) @app.get("/items/") async def read_items(): return [{"item": "Portal Gun"}, {"item": "Plumbus"}] @app.get("/users/") async def read_users(): return [{"username": "Rick"}, {"username": "Morty"}]

以上配置意味着访问/items//users/或任何已注册路由前,请求头必须同时携带X-Token: fake-super-secret-tokenX-Key: fake-super-secret-key,否则返回 400。适合做接口级开关、日志、限流、统一鉴权等横切逻辑;依赖中抛出的HTTPException会被 FastAPI 统一转换为对应状态码的 JSON 错误响应。

安全性:基于 Token 的认证

完整 Token 认证流程

下面是一个可运行的最小 Bearer Token 认证示例。先导入所需组件:

from fastapi import FastAPI, Depends, HTTPException from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from pydantic import BaseModel app = FastAPI()

使用OAuth2PasswordBearer创建一个 token 依赖,tokenUrl指明客户端应到哪个接口换取 token:

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

假设这是你的用户数据库(实际项目中替换为数据库查询,并务必使用真正的密码哈希):

fake_users_db = { "johndoe": { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", "hashed_password": "fakehashedsecret", "disabled": False, } }

创建用户模型:

class User(BaseModel): username: str email: str full_name: str disabled: bool

创建简单的认证辅助函数:

def fake_hash_password(password: str): return "fakehashed" + password def get_user(db, username: str): if username in db: user_dict = db[username] return User(**user_dict) def fake_decode_token(token: str): # 这个函数应该验证 token 并返回用户信息 # 这里我们只是简单地返回了用户名 return get_user(fake_users_db, token)

创建依赖,用于从请求中获取 token 并验证用户;同时实现登录接口/token(接收OAuth2PasswordRequestForm表单的username/password)和受保护的/users/me接口:

async def get_current_user(token: str = Depends(oauth2_scheme)): user = fake_decode_token(token) if not user: raise HTTPException( status_code=401, detail="Invalid authentication credentials", headers={"WWW-Authenticate": "Bearer"}, ) return user @app.post("/token") async def login(form_data: OAuth2PasswordRequestForm = Depends()): user = get_user(fake_users_db, form_data.username) if not user or user.hashed_password != fake_hash_password(form_data.password): raise HTTPException(status_code=400, detail="Incorrect username or password") return {"access_token": user.username, "token_type": "bearer"} @app.get("/users/me") async def read_users_me(current_user: User = Depends(get_current_user)): return current_user

整个流程串起来是:

  1. 客户端向POST /token提交用户名密码表单,OAuth2PasswordRequestForm负责解析usernamepassword(以及可选的scope);
  2. 校验通过后返回access_token(示例中直接返回用户名,生产环境应返回签名后的 JWT 或会话令牌);
  3. 客户端携带Authorization: Bearer <token>请求受保护接口;oauth2_scheme从请求头中提取 token 并注入get_current_user,验证失败时抛出 401 并附带WWW-Authenticate: Bearer响应头;
  4. 验证通过的用户对象注入read_users_me,直接返回当前用户信息。

这正是前文「全局依赖项」一节的进阶形态:把Depends(get_current_user)挂到具体路由,即可实现接口粒度的鉴权;OAuth2PasswordBearer还会在自动生成的 API 文档中渲染出标准的「Authorize」授权按钮。

HTTPS 和证书

应用层代码不需要为 HTTPS 做任何特殊处理:

from fastapi import FastAPI app = FastAPI() @app.get("/https") async def read_https(): return {"message": "Hello, HTTPS!"}

TLS 终结由 ASGI 服务器承担。启动uvicorn时指定证书和私钥即可,生产环境中应该使用真正的证书和私钥——可以从 Let's Encrypt 这类证书颁发机构获得免费证书,或者使用 OpenSSL 生成自签名证书:

uvicorn main:app --host 0.0.0.0 --port 443 --ssl-keyfile /path/to/your/key.pem --ssl-certfile /path/to/your/cert.pem

参数说明:--host 0.0.0.0监听所有网卡;--port 443使用 HTTPS 默认端口;--ssl-keyfile指向私钥文件(.pem);--ssl-certfile指向证书文件。配置生效后,FastAPI 应用即可通过https://访问,从源码结构看,FastAPI 本身未实现 TLS,加密完全由 uvicorn 的ssl上下文处理,因此也可以选择在 Nginx 等反向代理层终结 TLS 后再转发到 uvicorn。

适用前提与延伸

  • 版本前提:文中示例以 FastAPI0.103.1/ Python3.9.5为验证环境,Union[str, None]写法兼容性最好;Annotated新式元数据写法在 FastAPI 0.95+ 中已是主流推荐;
  • 运行依赖:所有代码都通过uvicorn启动;FormUploadFile功能额外依赖python-multipart
  • 自动文档:文中每个接口的参数、默认值、校验约束都会被 FastAPI 自动收集,生成 OpenAPI 文档与交互式调试页面,这是「类型提示 + 元数据」写法的主要回报之一;
  • 仓库内相关速查表:Python 基础语法见 Python 备忘清单,虚拟环境与包管理可查 pip、uv、conda;
  • 完整清单原文:本文全部代码与参数表均继承自 FastAPI 备忘清单,如需在线排版样式可参考仓库的 Quick Reference 排版说明。

【免费下载链接】reference面向开发者的技术速查清单(Cheat Sheets)集合,整理常见技术、工具与开发流程,帮助快速查阅关键信息,提高开发效率。项目地址: https://gitcode.com/GitHub_Trending/referen/reference

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询