FastAPI :看懂接口与请求流程
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
只写几行 Python,浏览器里就出现了一套可以直接测试的接口文档;参数传错时,框架还会主动告诉我们错在哪里。这种“写完马上看到结果”的体验,正是 FastAPI 对新手最有吸引力的地方。 今天讲述一下 FastAPI 的自动接口文档、参数类型和 Pydantic 数据模型,并结合项目代码重点学习依赖注入与中间件的作用、执行顺序及使用场景。 一、自动接口文档与项目启动
截图上半部分是接口列表:蓝色 from fastapi import FastAPI# 创建 FastAPI 应用对象,后续路由都注册到 app 上app = FastAPI()# 注册一个处理 GET / 请求的路由@app.get("/")async def root(): # 字典会被 FastAPI 自动转换成 JSON 响应 return {"message": "Hello World"}
项目可以选择一种依赖管理方式启动,不要混用不同环境: # uv:当前项目推荐uv syncuv run uvicorn main:app --reload# pippython -m venv .venv.\.venv\Scripts\Activate.ps1python -m pip install fastapi uvicornpython -m uvicorn main:app --reload# Poetrypoetry installpoetry run uvicorn main:app --reload
|
| 参数 | 通俗解释 | 示例 |
|---|---|---|
default | 客户端不传时采用的值 | default=10 |
... | 参数必须提供,没有默认值 | Path(...) |
min_length | 字符串最少字符数 | min_length=2 |
max_length | 字符串最多字符数 | max_length=10 |
gt | 必须大于,不包含边界值 | gt=0 |
ge | 必须大于等于 | ge=1 |
lt | 必须小于,不包含边界值 | lt=101 |
le | 必须小于等于 | le=60 |
description | 显示在 /docs 中的说明 | description="当前页" |
💡 g 是 greater,l 是 less,e 是 equal,缩写末尾带 e 就表示包含等号。
请求模型、响应模型和注册路由放在同一个代码块中,更容易看出它们的关系:
# 请求模型:检查客户端提交的用户名和密码class User(BaseModel): username: str = Field(default="张三", min_length=2, max_length=10) password: str = Field(min_length=3, max_length=20)# 响应模型:只允许接口返回 usernameclass RegisterResponse(BaseModel): username: str# response_model 会检查并过滤路由的返回结果@app.post("/register", response_model=RegisterResponse)async def register(user: User): # 不返回 password,避免泄露用户密码 return {"username": user.username}user: User 用来约束请求参数的类型,response_model=RegisterResponse 用来约束响应结果的类型。
Field 用来给模型字段补充默认值、长度、数值范围和文档说明:
| 参数 | 通俗解释 | 示例 |
|---|---|---|
default | 客户端不传时使用默认值 | default="张三" |
default_factory | 调用函数生成默认值 | default_factory=list |
min_length | 字符串最少字符数 | min_length=2 |
max_length | 字符串最多字符数 | max_length=10 |
gt | 数字必须大于指定值 | gt=0 |
ge | 数字必须大于等于指定值 | ge=1 |
lt | 数字必须小于指定值 | lt=101 |
le | 数字必须小于等于指定值 | le=100 |
description | 在 /docs 中说明字段 | description="用户名" |
examples | 在 /docs 中提供示例值 | examples=["小明"] |
✅ 开头截图中的
User、News等Schemas,就是 FastAPI 根据 Pydantic 模型生成的数据结构说明。
新闻列表和用户列表都需要分页参数。为了避免重复,可以把参数提取成公共依赖:
# 公共依赖:集中接收并校验分页参数async def common_parameters( page: int = Query(1, ge=1), pageSize: int = Query(10, le=60),): # 返回值会注入使用该依赖的路由参数中 return {"page": page, "pageSize": pageSize}需要分页的路由通过 Depends 使用它:
# Depends 会先执行 common_parameters,再把结果传给 commons@app.get("/news/news_list")async def get_news_list(commons=Depends(common_parameters)): return commons# 多个路由可以复用同一个依赖,不必重复编写分页校验@app.get("/user/user_list")async def get_user_list(commons=Depends(common_parameters)): return commonsDepends(common_parameters) 可以理解为:“执行当前路由前,先运行 common_parameters,再把结果交给我。”
请求 /user/user_list?page=2&pageSize=20 时,FastAPI 会:
找到目标路由,并发现其中的 Depends。
调用 common_parameters,读取并校验分页参数。
将 {"page": 2, "pageSize": 20} 放入 commons。
最后执行 get_user_list 中的代码。
🧩
Depends让公共逻辑可以复用,并由 FastAPI 自动安排执行顺序。
当前项目注册了两个 HTTP 中间件:
# 先注册的中间件位于内层@app.middleware("http")async def middleware2(request, call_next): # call_next 之前:处理进入应用的请求 print("中间件2 start") # 把请求交给下一层中间件或路由 response = await call_next(request) # call_next 之后:处理路由返回的响应 print("中间件2 end") return response# 后注册的中间件位于外层,因此请求会先进入这里@app.middleware("http")async def middleware1(request, call_next): print("中间件1 start") # 等待内层中间件和路由执行完成 response = await call_next(request) print("中间件1 end") # 将最终响应返回给客户端 return responserequest 是当前请求,call_next 表示继续执行下一层,response 是后续流程返回的响应。await call_next(request) 之前处理进入的请求,之后处理返回的响应。
从代码位置看,middleware2 在上面,middleware1 在下面。后注册的 middleware1 会包在外层,所以顺序是:
middleware1 start middleware2 start 路由执行 middleware2 endmiddleware1 end请求进入时按代码位置自下往上,响应返回时再反向执行,这就是“洋葱模型”。
🔄
start部分处理进入的请求,end部分处理返回的响应。
常见需求可以直接通过下表判断:
| 实际需求 | 是否所有请求都需要 | 路由是否需要结果 | 选择 | 原因 |
|---|---|---|---|---|
| 记录访问日志 | 是 | 否 | 中间件 | 每个请求都要执行 |
| 统计完整请求耗时 | 是 | 否 | 中间件 | 需要包住请求与响应全过程 |
| 给所有响应添加响应头 | 是 | 否 | 中间件 | 需要在路由返回后统一修改 |
| 统一处理跨域 | 是 | 否 | 中间件 | 属于整个应用的共同规则 |
| 维护期间拦截请求 | 是 | 否 | 中间件 | 可以不调用 call_next,直接返回响应 |
| 列表接口共用分页参数 | 否 | 是 | 依赖注入 | 只有列表需要,路由还要使用结果 |
| 部分接口读取当前用户 | 否 | 是 | 依赖注入 | 用户信息要交给路由继续使用 |
| 管理接口检查权限 | 否 | 不一定 | 依赖注入 | 权限要求与具体路由有关 |
| 多个接口共用查询参数 | 否 | 是 | 依赖注入 | 可以统一校验并注入结果 |
🧭 关心“每个请求都要做什么”,选择中间件;关心“这个路由需要什么”,选择依赖注入。
现在,我们已经从 /docs 看到了接口如何生成,也理清了参数类型、Pydantic、依赖注入和中间件之间的关系。
阅读原文:点击这里