目录
[1.1 路由系统详解](#1.1 路由系统详解)
[1.1.1 路径操作装饰器](#1.1.1 路径操作装饰器)
[1.1.2 路径参数和验证](#1.1.2 路径参数和验证)
[1.2 请求数据处理](#1.2 请求数据处理)
[1.2.1 查询参数](#1.2.1 查询参数)
[1.2.2 请求体](#1.2.2 请求体)
[1.3 响应模型和状态码](#1.3 响应模型和状态码)
[基于 FastAPI 路由内容的 5 道多选题](#基于 FastAPI 路由内容的 5 道多选题)
[2.1 依赖注入系统](#2.1 依赖注入系统)
[2.1.1 基础依赖注入](#2.1.1 基础依赖注入)
[2.1.2 类依赖和参数化依赖](#2.1.2 类依赖和参数化依赖)
[2.1.3 依赖项的嵌套使用](#2.1.3 依赖项的嵌套使用)
[2.1.4 带有子依赖的类](#2.1.4 带有子依赖的类)
[2.1.5 在路径装饰器中使用依赖](#2.1.5 在路径装饰器中使用依赖)
[2.1.6 依赖项的高级用法](#2.1.6 依赖项的高级用法)
[2.1.7 实际应用场景](#2.1.7 实际应用场景)
[2.1.8 依赖注入的优势](#2.1.8 依赖注入的优势)
[2.1.9 最佳实践](#2.1.9 最佳实践)
[基于 FastAPI 依赖注入内容的 5 道多选题](#基于 FastAPI 依赖注入内容的 5 道多选题)
FastAPI 的路由与依赖注入是其核心特性,二者协同实现高效、规范的接口开发。路由系统支持 GET、POST、PUT 等多种 HTTP 方法,通过路径参数(如 {item_id})和查询参数(Query 封装)实现灵活传参,结合类型注解与 Path、Query 验证规则(如数值范围、字符串长度、正则匹配),自动完成参数校验与类型转换,同时生成交互式接口文档。请求体通过继承 pydantic.BaseModel 的类定义,借助 Field 配置字段约束,支持结构化数据传输与校验 ;响应模型同样基于 BaseModel,可指定返回结构、过滤字段,配合 status_code 自定义响应状态码,提升接口规范性。
1.1 什么是 Starlette?
Starlette 是一个轻量级的 ASGI(Asynchronous Server Gateway Interface)框架,专为构建异步 Web 应用设计。它是 FastAPI 的底层框架,提供了路由、请求处理、中间件、WebSocket 支持等核心功能。Starlette 的设计目标是简单、高效,同时保持足够的灵活性,适用于各种 Web 开发场景。
1.2 Starlette 的核心特性
异步支持:基于 Python 的 asyncio,支持异步 I/O 操作,适合高并发场景。
路由系统:提供直观的路径操作装饰器,用于定义 API 端点。
请求与响应处理:内置对 HTTP 请求和响应的支持,支持 JSON、表单数据等格式。
中间件:允许开发者在请求处理前后添加自定义逻辑。
WebSocket 支持:支持实时双向通信,适用于聊天应用等场景。
1.3 Starlette 在 FastAPI 中的作用
FastAPI 直接继承了 Starlette 的所有功能,例如路由、请求处理和中间件。FastAPI 的 @app.get()、@app.post() 等装饰器实际上是对 Starlette 路由系统的封装。换句话说,FastAPI 在 Starlette 的基础上增加了类型检查、自动文档生成等高级特性。
1.4 Starlette 示例
以下是一个简单的 Starlette 示例,展示如何定义路由和处理请求:
from starlette.applications import Starlette from starlette.responses import JSONResponse from starlette.routing import Route async def homepage(request): return JSONResponse({"message": "欢迎使用 Starlette!"}) async def user(request): user_id = request.path_params["user_id"] return JSONResponse({"user_id": user_id}) app = Starlette(debug=True, routes=[ Route("/", homepage), Route("/user/{user_id:int}", user), ]) # 运行方式:使用 https://zhida.zhihu.com/search?content_id=255887007&content_type=Article&match_order=1&q=uvicorn&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NzEzMjQyNzQsInEiOiJ1dmljb3JuIiwiemhpZGFfc291cmNlIjoiZW50aXR5IiwiY29udGVudF9pZCI6MjU1ODg3MDA3LCJjb250ZW50X3R5cGUiOiJBcnRpY2xlIiwibWF0Y2hfb3JkZXIiOjEsInpkX3Rva2VuIjpudWxsfQ.KZTrimBTYBZ4Vmwp5iqsE2Za9IoCUuSEbiZK-zHysZg&zhida_source=entity 启动 # uvicorn script_name:app --reload
在这个例子中:
- • 定义了两个路由:/ 返回欢迎信息,/user/{user_id:int} 返回动态的用户 ID。
- • 使用 JSONResponse 返回 JSON 格式的响应。
- • 通过 request.path_params 获取路径参数。
运行后,访问 http://127.0.0.1:8000/ 会返回 {"message": "欢迎使用 Starlette!"},访问 http://127.0.0.1:8000/user/123 会返回 {"user_id": 123}。
**依赖注入系统以声明式方式管理组件依赖,支持函数依赖、类依赖及参数化依赖,依赖项可嵌套形成依赖链(内层依赖为子依赖项),满足认证、权限校验、资源管理等复杂需求。**通过 Depends 关键字声明依赖,FastAPI 自动解析并注入依赖返回值;路径装饰器中可通过 dependencies 参数声明仅执行逻辑不传递返回值的依赖(如认证校验)。依赖项支持 yield 语法实现资源创建与自动清理(如数据库连接关闭),且默认在单个请求中缓存依赖结果,提升执行效率。二者结合让代码模块化、可测试性大幅提升,兼顾开发效率与接口质量。
1.5 路由系统详解
1.5.1 路径操作装饰器
from fastapi import FastAPI, Path, Query
app = FastAPI()
# 各种HTTP方法
@app.get("/items/{item_id}")
async def get_item(item_id: int):
return {"method": "GET", "item_id": item_id}
@app.post("/items/")
async def create_item():
return {"method": "POST"}
@app.put("/items/{item_id}")
async def update_item(item_id: int):
return {"method": "PUT", "item_id": item_id}
@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
return {"method": "DELETE", "item_id": item_id}
@app.patch("/items/{item_id}")
async def partial_update(item_id: int):
return {"method": "PATCH", "item_id": item_id}
1.5.2 路径参数和验证
from fastapi import Path
@app.get("/items/{item_id}")
async def read_item(
item_id: int = Path(..., title="商品ID", description="商品的唯一标识符", ge=1, le=1000),
q: str = Query(None, min_length=3, max_length=50)
):
"""
获取商品信息
- **item_id**: 商品ID,必须是1-1000之间的整数
- **q**: 可选查询参数,长度3-50字符
"""
return {"item_id": item_id, "q": q}
1.6 请求数据处理
1.6.1 查询参数
from fastapi import Query
from typing import List, Optional
@app.get("/items/")
async def read_items(
skip: int = Query(0, description="跳过的记录数"),
limit: int = Query(100, le=1000, description="返回的记录数"),
tags: List[str] = Query([], description="标签过滤")
):
return {"skip": skip, "limit": limit, "tags": tags}
1.6.2 请求体
from pydantic import BaseModel, Field
class User(BaseModel):
username: str = Field(..., min_length=3, max_length=50, example="john_doe")
email: str = Field(..., regex=r"^[\w\.-]+@[\w\.-]+\.\w+$", example="john@example.com")
age: int = Field(..., ge=0, le=150, example=25)
is_active: bool = Field(True, description="用户是否激活")
@app.post("/users/")
async def create_user(user: User):
return {"user": user.dict(), "message": "用户创建成功"}
1.7 响应模型和状态码
from fastapi import status
from pydantic import BaseModel
class UserResponse(BaseModel):
id: int
username: str
email: str
is_active: bool
@app.post(
"/users/",
response_model=UserResponse,
status_code=status.HTTP_201_CREATED,
summary="创建用户",
description="创建一个新用户并返回用户信息"
)
async def create_user(user: User):
# 模拟创建用户
user_data = user.dict()
user_data["id"] = 1 # 模拟ID生成
return UserResponse(**user_data)
基于 FastAPI 路由内容的 5 道多选题
题目 1:关于 FastAPI 路径操作装饰器,以下说法正确的有()
A. 支持的 HTTP 方法包括 GET、POST、PUT、DELETE、PATCH
B. 路径参数(如{item_id})需在接口函数中声明对应参数,且支持类型注解
C. @app.get("/items/{item_id}")中,item_id只能接收字符串类型参数
D. 路径操作装饰器直接绑定接口函数,FastAPI 会自动生成接口文档
答案:ABD
解析:C 错误,原文 3.1.1 中item_id声明为int类型,FastAPI 支持路径参数的类型注解(如int),会自动进行类型校验和转换;A 对应 3.1.1 中明确列出的 5 种 HTTP 方法;B 符合 3.1.1 示例中 "路径参数item_id与函数参数item_id: int对应" 的逻辑;D 是 FastAPI 的核心特性,路径操作装饰器会自动整合接口信息到文档。
题目 2:关于 FastAPI 路径参数和Path验证,正确的描述有()
A. Path(..., ge=1, le=1000)表示该参数为必填项,且值需在 1-1000 之间
B. title和description参数用于设置接口文档中的字段说明,不影响功能逻辑
C. 路径参数的类型注解只能是int,不能是其他类型(如str)
D. Path需从fastapi模块导入,用于增强路径参数的验证和描述能力
答案:ABD
解析:C 错误,路径参数支持多种类型注解(如str、float等),原文 3.1.1 中item_id为int仅为示例;A 中...表示必填项,ge(大于等于)、le(小于等于)是Path的数值验证参数,对应 3.1.2 示例;B 符合 3.1.2 中title(字段标题)和description(字段描述)的作用;D 对应 3.1.2 代码中from fastapi import Path的导入逻辑和Path的核心用途。
题目 3:关于 FastAPI 查询参数和Query验证,以下说法正确的有()
A. Query(0, description="跳过的记录数")表示查询参数默认值为 0,且有描述说明
B. 支持List[str]类型注解,接收多个查询参数值(如?tags=book&tags=tech)
C. min_length=3, max_length=50仅适用于int类型参数,不适用于str类型
D. Query(None)表示该查询参数为可选参数,未传递时值为None
答案:ABD
解析:C 错误,min_length和max_length是字符串类型的验证参数,对应 3.1.2 中q: str = Query(None, min_length=3, max_length=50)的示例;A 对应 3.2.1 中skip: int = Query(0, description="跳过的记录数")的写法;B 符合 3.2.1 中tags: List[str] = Query([], description="标签过滤")的逻辑,支持多值查询参数;D 是Query(None)的核心含义,对应 3.1.2 和 3.2.1 中可选查询参数的定义。
题目 4:关于 FastAPI 请求体和pydantic.BaseModel,正确的描述有()
A. 请求体需通过继承BaseModel的类来定义字段结构和验证规则
B. Field(..., regex=r"^[\w\.-]+@[\w\.-]+\.\w+$")用于验证邮箱格式的字符串
C. 定义请求体类时,所有字段必须设置...(必填),不能有默认值
D. 接口函数接收请求体参数后,可通过.dict()方法将其转换为字典类型
答案:ABD
解析:C 错误,3.2.2 中is_active: bool = Field(True, description="用户是否激活")设置了默认值True,说明请求体字段支持默认值(非必填);A 对应 3.2.2 中User类继承BaseModel的定义方式;B 符合 3.2.2 中邮箱字段的正则验证逻辑;D 对应 3.2.2 示例中user.dict()的用法,可将 Pydantic 模型实例转为字典。
题目 5:关于 FastAPI 响应模型和状态码,以下说法正确的有()
A. response_model=UserResponse用于指定接口返回数据的结构和字段过滤
B. status_code=status.HTTP_201_CREATED表示接口成功时返回 201 状态码(创建成功)
C. 响应模型类UserResponse无需继承BaseModel,直接定义字段即可
D. summary和description参数用于设置接口文档中的接口说明,会显示在自动生成的文档中
答案:ABD
解析:C 错误,3.3 中UserResponse明确继承pydantic.BaseModel,响应模型必须基于BaseModel定义才能实现结构校验和文档生成;A 对应 3.3 中response_model=UserResponse的核心作用(限制返回字段、结构校验);B 符合 3.3 中创建用户接口返回 201 状态码的逻辑(HTTP 201 对应资源创建成功);D 对应 3.3 中summary(接口摘要)和description(接口详细描述)的用法,会同步到 FastAPI 自动生成的接口文档中。
2.1 依赖注入系统
依赖注入是FastAPI框架的核心特性之一,它允许您以声明式的方式管理和使用组件依赖关系,使代码更加模块化、可测试和可维护。
2.1.1 基础依赖注入
from fastapi import Depends, FastAPI
app = FastAPI()
# 简单的依赖函数
def get_db():
# 模拟数据库连接
db = {"connected": True}
try:
yield db # 使用yield而不是return,支持资源清理
finally:
db["connected"] = False # 清理资源
# 使用依赖
@app.get("/items/")
async def read_items(db: dict = Depends(get_db)):
return {"database_status": db["connected"]}
在这个例子中:
get_db()是一个依赖函数,它创建并返回一个数据库连接read_items函数通过Depends(get_db)声明它需要get_db函数提供的依赖- FastAPI会在处理请求时自动调用
get_db()并将其返回值传递给read_items
2.1.2 类依赖和参数化依赖
from fastapi import Depends
class Pagination:
def __init__(self, skip: int = 0, limit: int = 100):
self.skip = skip
self.limit = limit
def get_pagination(skip: int = 0, limit: int = 100) -> Pagination:
return Pagination(skip=skip, limit=limit)
@app.get("/items/")
async def read_items(pagination: Pagination = Depends(get_pagination)):
return {
"skip": pagination.skip,
"limit": pagination.limit,
"message": f"查询第{pagination.skip}到{pagination.skip + pagination.limit}条记录"
}
2.1.3 依赖项的嵌套使用
依赖项可以依赖于其他依赖项,形成依赖链:
from fastapi import Depends, Header, HTTPException
def get_token(token: str = Header(...)):
if not token:
raise HTTPException(status_code=401, detail="缺少认证令牌")
return token
def get_current_user(token: str = Depends(get_token)):
# 使用token获取用户信息
# 这里模拟从数据库获取用户
if token == "valid-token":
return {"username": "john", "token": token}
raise HTTPException(status_code=401, detail="无效的认证令牌")
@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
return current_user
2.1.4 带有子依赖的类
from typing import Optional
from fastapi import Depends, Query
class CommonQueryParams:
def __init__(
self,
q: Optional[str] = None,
skip: int = 0,
limit: int = 100
):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/users/")
async def read_users(commons: CommonQueryParams = Depends()):
response = {}
if commons.q:
response.update({"q": commons.q})
response.update(
{"skip": commons.skip, "limit": commons.limit}
)
return response
2.1.5 在路径装饰器中使用依赖
有时候,我们不需要在函数内部使用依赖项返回值,但需要执行依赖项逻辑(如认证、权限验证):
from fastapi import Depends, HTTPException, status
async def verify_token(token: str = Header(...)):
if token != "valid-token":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="无效的认证令牌"
)
async def verify_permissions(current_user: dict = Depends(get_current_user)):
if current_user.get("role") != "admin":
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="权限不足"
)
@app.get("/admin/dashboard", dependencies=[Depends(verify_token), Depends(verify_permissions)])
async def read_admin_dashboard():
return {"message": "欢迎访问管理员面板"}
2.1.6 依赖项的高级用法
使用yield进行资源管理
当依赖项需要资源清理时(如关闭数据库连接),可以使用 yield 而不是 return:
from sqlalchemy.orm import Session
from fastapi import Depends
def get_db():
db = SessionLocal()
try:
yield db # 在yield之前的部分在请求处理前执行
finally:
db.close() # 在yield之后的部分在请求处理后执行
依赖项的缓存机制
FastAPI默认在单个请求中缓存依赖项的返回值,即使同一个依赖项被多次使用也只会调用一次:
async def get_db():
print("创建数据库连接") # 这个打印只会在一次请求中出现一次
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/items/")
async def read_items(db: Session = Depends(get_db), another_db: Session = Depends(get_db)):
# 尽管使用了两次get_db依赖,但"创建数据库连接"只会打印一次
return {"message": "获取数据成功"}
禁用依赖项缓存
如果需要每次都重新计算依赖项,可以使用 use_cache=False 参数:
@app.get("/items/")
async def read_items(
db: Session = Depends(get_db, use_cache=False),
another_db: Session = Depends(get_db, use_cache=False)
):
# 现在每次使用get_db都会重新调用
return {"message": "获取数据成功"}
2.1.7 实际应用场景
数据库会话管理
from sqlalchemy.orm import Session
from fastapi import Depends, FastAPI
app = FastAPI()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.post("/users/")
async def create_user(user: UserCreate, db: Session = Depends(get_db)):
db_user = User(**user.dict())
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
用户认证
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="无法验证凭据",
headers={"WWW-Authenticate": "Bearer"},
)
try:
# 验证token并获取用户信息
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username=username)
if user is None:
raise credentials_exception
return user
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
权限控制
async def get_current_active_user(
current_user: User = Depends(get_current_user)
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="用户已被禁用")
return current_user
@app.get("/users/me/items")
async def read_own_items(
current_user: User = Depends(get_current_active_user)
):
return [{"item_id": "Foo", "owner": current_user.username}]
2.1.8 依赖注入的优势
- 代码复用:将常用功能(如数据库连接、认证)定义为依赖项,可在多个路径操作中重复使用
- 减少代码重复:避免在每个路径操作函数中重复相同的逻辑
- 简化测试:可以轻松替换依赖项进行单元测试
- 提高可维护性:依赖项的修改只需要在一处进行
- 自动集成:FastAPI自动处理依赖项的解析和注入
2.1.9 最佳实践
- 使用yield进行资源管理:对于需要清理的资源(如数据库连接),使用yield而不是return
- 合理拆分依赖项:将复杂的依赖项拆分为多个小依赖项,提高复用性
- 类型提示:为依赖项提供准确的类型提示,提高代码可读性和IDE支持
- 错误处理:在依赖项中适当处理错误情况,抛出HTTPException
- 依赖项命名:使用清晰的命名约定,使依赖项的用途一目了然
通过合理使用FastAPI的依赖注入系统,您可以构建出结构清晰、易于扩展的Web应用程序。依赖注入不仅是一种技术实现,更是一种设计思想,它帮助您编写更加模块化、可测试和可维护的代码。
基于 FastAPI 依赖注入内容的 5 道多选题
题目 1:关于 FastAPI 基础依赖注入,以下说法正确的有()
A. 依赖函数可以通过yield实现资源清理,finally块中的代码会在请求处理后执行
B. 使用Depends()声明依赖时,FastAPI 会自动调用依赖函数并传递返回值给接口函数
C. 依赖函数只能返回字典类型的数据,不能返回类实例
D. 基础依赖注入中,Depends需要从fastapi模块导入
答案:ABD
解析 :C 错误,依赖函数可以返回任意类型,包括类实例(如 4.1.2 中的Pagination类实例);A 对应 4.1.1 和 4.1.6 的yield资源管理逻辑;B 是基础依赖注入的核心机制;D 符合代码示例中from fastapi import Depends的写法。
题目 2:关于 FastAPI 类依赖和参数化依赖,下列描述正确的有()
A. 可以定义类作为依赖的返回类型,接口函数可直接使用类实例的属性
B. CommonQueryParams类作为依赖时,接口中声明commons: CommonQueryParams = Depends()即可自动实例化
C. 参数化依赖只能接收int类型的参数,不能接收str或Optional类型
D. 类依赖的初始化方法可以设置默认参数,如skip: int = 0
答案:ABD
解析 :C 错误,4.1.4 中CommonQueryParams的q参数是Optional[str]类型,说明参数化依赖支持多种类型;A 对应 4.1.2 中Pagination类的使用;B 对应 4.1.4 的类依赖写法;D 符合 4.1.2 和 4.1.4 中类初始化方法的参数定义。
题目 3:FastAPI 依赖项的嵌套使用(依赖链),以下说法正确的有()
A. 依赖函数可以依赖其他依赖函数,如get_current_user依赖get_token
B. 嵌套依赖中,若内层依赖抛出HTTPException,外层会直接传递该异常给客户端
C. 嵌套依赖只能有两层,不能超过三层
D. Header(...)可以用来获取请求头中的参数,...表示该参数为必填项
答案:ABD
解析 :C 错误,依赖链没有层数限制,只要逻辑合理即可嵌套;A 对应 4.1.3 的依赖链示例;B 符合 4.1.3 中get_token抛出 401 异常的逻辑;D 是Header参数的基础用法,符合 4.1.3 的代码示例。
题目 4:关于 FastAPI 在路径装饰器中使用依赖,正确的有()
A. 路径装饰器中通过dependencies参数声明依赖,格式为列表,元素是Depends(依赖函数)
B. 装饰器中声明的依赖,其返回值不会传递给接口函数,但会执行依赖的逻辑
C. 装饰器中的依赖只能用于认证,不能用于权限验证
D. 可以同时声明多个依赖,如同时验证令牌和权限
答案:ABD
解析 :C 错误,4.1.5 中verify_token(认证)和verify_permissions(权限验证)都用于装饰器依赖;A 对应 4.1.5 中dependencies=[Depends(verify_token), Depends(verify_permissions)]的写法;B 是装饰器依赖的核心特点(只执行逻辑,不传递返回值);D 符合 4.1.5 的示例逻辑。
题目 5:关于 FastAPI 依赖项的高级用法(资源管理、缓存),正确的有()
A. 使用yield的依赖函数,yield前的代码在请求处理前执行,yield后的代码(如finally块)在请求处理后执行
B. FastAPI 默认在单个请求中缓存依赖项返回值,同一个依赖多次使用只会调用一次
C. 依赖项的缓存机制是全局的,不同请求会共享同一个依赖返回值
D. yield可以替代return实现依赖返回值,同时支持资源清理
答案:ABD
解析 :C 错误,缓存机制仅针对 "单个请求",不同请求会重新调用依赖函数;A 对应 4.1.6 的资源管理逻辑;B 符合 4.1.6 中 "创建数据库连接" 只打印一次的示例;D 是yield在依赖函数中的核心作用(返回值 + 资源清理)。