FastAPI 请求详解:全面掌握各种请求类型处理
FastAPI 是一个现代、快速(高性能)的 Python Web 框架,基于标准的 Python 类型提示构建,支持异步处理,内置自动生成 API 文档(Swagger UI 和 ReDoc),并以极简语法实现强大的请求处理能力。本文将系统性地介绍 FastAPI 如何处理各种类型的 HTTP 请求,涵盖路径参数、查询参数、请求体、文件上传、表单数据、Header/Cookie 等核心功能,并结合 Pydantic 验证、异常处理和最佳实践,帮助你构建健壮、可维护的 RESTful API。
📅 FastAPI 版本兼容性:本文基于 fastapi>=0.95
编写,适用于当前主流版本
一、HTTP 方法(HTTP Verbs)与路由设计
在 RESTful 架构中,不同的 HTTP 方法对应不同的资源操作语义。FastAPI 使用装饰器绑定路由与处理函数,简洁直观。
from fastapi import FastAPIapp = FastAPI()@app.get("/items") # 获取资源列表
async def read_items():return {"message": "获取所有 items"}@app.post("/items") # 创建新资源
async def create_item():return {"message": "创建 item"}@app.put("/items/{id}") # 全量更新资源(幂等)
async def update_item(id: int):return {"message": f"全量更新 item {id}"}@app.patch("/items/{id}") # 部分更新资源
async def partial_update_item(id: int):return {"message": f"部分更新 item {id}"}@app.delete("/items/{id}") # 删除资源(幂等)
async def delete_item(id: int):return {"message": f"删除 item {id}"}@app.options("/items") # 获取服务器支持的操作方法
async def options_items():return {"allow": "GET, POST, PUT, DELETE, OPTIONS"}@app.head("/items") # 获取响应头(无响应体)
async def head_items():return {}@app.trace("/items") # 回显请求(调试用途)
async def trace_items():return {"message": "TRACE 请求已收到"}
✅ RESTful 设计原则回顾
方法 | 幂等性 | 安全性 | 用途说明 |
| ✅ 幂等 | ✅ 安全 | 获取资源,不应产生副作用 |
| ❌ 非幂等 | ❌ 不安全 | 创建资源,每次调用可能生成新资源 |
| ✅ 幂等 | ❌ 不安全 | 全量替换资源,不存在则创建 |
| ❌ 非幂等 | ❌ 不安全 | 局部更新资源 |
| ✅ 幂等 | ❌ 不安全 | 删除资源,多次调用结果一致 |
💡 提示:尽量遵循 REST 语义,避免滥用 POST
承担所有操作。
二、路径参数(Path Parameters)——动态路由
路径参数用于捕获 URL 中的动态部分,如用户 ID、商品编号等。
1. 基础用法 + 类型验证
@app.get("/users/{user_id}")
def get_user(user_id: int):return {"user_id": user_id, "type": type(user_id).__name__}
- 访问
/users/123
→ 返回{"user_id": 123, "type": "int"}
- 访问
/users/abc
→ 自动返回422 Unprocessable Entity
错误(类型不匹配)
FastAPI 借助 Pydantic 实现了自动类型转换与验证。支持的类型包括:
int
,float
,bool
,str
datetime
,date
,time
UUID
,Path
,List
,Dict
等
2. 多级路径参数
@app.get("/users/{user_id}/orders/{order_id}")
def get_user_order(user_id: int, order_id: str):return {"user_id": user_id, "order_id": order_id}
URL 示例:/users/42/orders/ORD-1001
3. 包含斜杠的路径(通配符路径)
使用 path()
类型表示可包含 /
的路径段:
from fastapi import Path@app.get("/files/{file_path:path}")
def read_file(file_path: str):return {"file_path": file_path}
示例:
/files/path/to/file.txt
→file_path = "path/to/file.txt"
/files/config.json
→file_path = "config.json"
⚠️ 注意:{file_path:path}
必须是最后一个路径段,否则会捕获后续路径。
三、查询参数(Query Parameters)——灵活过滤与分页
查询参数是 URL ?
后的部分,用于传递可选参数,如分页、搜索关键词等。
1. 基本查询参数(带默认值)
python
@app.get("/items")
def read_items(skip: int = 0, limit: int = 10, q: str = None):params = {"skip": skip, "limit": limit}if q:params["q"] = qreturn params
请求示例:
GET /items?q=phone&skip=5&limit=20
→ 返回 {"skip": 5, "limit": 20, "q": "phone"}
- 有默认值 → 可选参数
- 无默认值 → 必填参数(会自动校验)
2. 显式定义查询参数(使用 Query
)
Query
提供更丰富的验证和文档控制:
from fastapi import Query@app.get("/items/required")
def required_query(q: str = Query(..., min_length=3, description="搜索关键词")):return {"q": q}
...
表示必填min_length=3
:最小长度description
:出现在 Swagger 文档中
3. 多值查询参数(List)
@app.get("/items/tags")
def filter_by_tags(tags: list[str] = Query(["electronics", "mobile"])) -> dict:return {"tags": tags}
请求示例:
GET /items/tags?tags=phone&tags=apple
→ tags = ["phone", "apple"]
4. 查询参数约束(高级验证)
@app.get("/items/search")
def search_items(q: str = Query(..., min_length=2, max_length=50, regex="^[a-zA-Z0-9_\\s]+$"),page: int = Query(1, gt=0, le=1000),size: int = Query(10, ge=1, le=100),sort: str = Query("created_at", enum=["name", "price", "created_at"])
):return {"q": q, "page": page, "size": size, "sort": sort}
regex
:正则表达式校验enum
:限制可选值gt
,ge
,lt
,le
:数值范围
✅ 最佳实践:为查询参数添加合理的默认值和边界限制,防止恶意请求耗尽资源。
四、请求体(Request Body)——接收复杂数据
使用 Pydantic 模型定义 JSON 请求体结构,实现自动解析、类型转换和验证。
1. 定义 Pydantic 模型
from pydantic import BaseModel
from typing import Optionalclass Item(BaseModel):name: strdescription: Optional[str] = Noneprice: floattax: Optional[float] = None = None
2. 接收请求体
@app.post("/items")
def create_item(item: Item):total_price = item.price + (item.tax or 0)return {"item": item.dict(),"total_price": total_price}
请求示例(JSON):
{"name": "MacBook Pro","description": "Apple M1 Pro, 16GB RAM","price": 1999.99,"tax": 199.99
}
3. 多个请求体参数(使用 Body
)
当需要接收多个 JSON 字段时,使用 embed=True
包装:
from fastapi import Body@app.post("/items/{item_id}")
def update_item(item_id: int,item: Item = Body(..., embed=True),importance: int = Body(..., gt=0, embed=True)
):return {"item_id": item_id, "item": item, "importance": importance}
请求体示例:
{"item": {"name": "Laptop","price": 1200},"importance": 5
}
4. 混合参数(路径 + 查询 + 请求体)
@app.put("/items/{item_id}")
def complex_update(item_id: int,q: str = None,item: Item = Body(...)
):result = {"item_id": item_id}if q:result["q"] = qresult["item"] = itemreturn result
⚠️ 注意顺序:路径参数 → 查询参数 → 请求体参数(顺序不影响功能,但建议保持一致)
五、Header 与 Cookie 参数
用于获取客户端元信息或会话标识。
1. 读取 Cookie
from fastapi import Cookie@app.get("/profile")
def get_profile(session_id: str = Cookie(None)):if not session_id:return {"error": "未登录"}return {"session_id": session_id}
2. 读取 Header
from fastapi import Header@app.get("/info")
def get_client_info(user_agent: str = Header(...),x_token: list[str] = Header(None), # 支持重复 Headeraccept_language: str = Header("zh-CN")
):return {"user_agent": user_agent,"x_token": x_token,"language": accept_language}
✅ 常见用途:
User-Agent
:识别客户端设备Authorization
:JWT 认证(通常用Depends
提取)X-Request-ID
:链路追踪Accept-Language
:国际化支持
六、文件上传(File Upload)
使用 UploadFile
类处理 multipart/form-data
请求。
1. 单文件上传
from fastapi import File, UploadFile@app.post("/upload/")
async def upload_file(file: UploadFile = File(...)):contents = await file.read()return {"filename": file.filename,"content_type": file.content_type,"size": len(contents),"encoding": file.headers.get("content-transfer-encoding")}
2. 多文件上传
@app.post("/upload/multiple/")
async def upload_multiple(files: list[UploadFile] = File(...)):results = []for file in files:content = await file.read()results.append({"filename": file.filename,"size": len(content),"content_type": file.content_type})return results
📌 前端示例(HTML):
<form action="/upload/multiple/" method="post" enctype="multipart/form-data"><input type="file" name="files" multiple><button type="submit">上传</button>
</form>
⚠️ 安全建议:
- 限制文件大小(使用
max_length
) - 校验文件类型(MIME 类型 + 文件头)
- 存储路径避免用户可控
- 异步写入磁盘(避免阻塞)
七、表单数据(Form Data)
处理 application/x-www-form-urlencoded
格式的表单提交。
from fastapi import Form@app.post("/login/")
def login(username: str = Form(...), password: str = Form(...)):# 实际项目中应使用 OAuth2 或 JWTreturn {"username": username}
🔍 注意:不能同时使用 Form
和 Body
接收 JSON,FastAPI 会根据 Content-Type
自动选择解析方式。
八、原始请求对象(Request)——深入底层
获取完整的请求上下文信息:
from fastapi import Request@app.get("/debug")
async def debug_request(request: Request):return {"url": str(request.url),"method": request.method,"headers": dict(request.headers),"query_params": dict(request.query_params),"path_params": request.path_params,"client": request.client,"cookies": request.cookies,"body": await request.body() # 注意:只能读取一次}
⚠️ 警告:await request.body()
会消耗流,后续中间件或函数无法再次读取。
九、请求验证失败处理(422 Error)
当请求数据不符合模型定义时,FastAPI 自动返回 422 Unprocessable Entity
。
你可以自定义错误响应格式:
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):return JSONResponse(status_code=422,content={"code": 422,"message": "数据验证失败,请检查输入","details": [{"field": ".".join(str(loc) for loc in error["loc"]),"message": error["msg"],"type": error["type"],"input": error.get("input", None)}for error in exc.errors()]})
✅ 生产建议:将此异常处理器封装为通用模块,统一 API 错误格式。
十、最佳实践与常见陷阱
实践 | 说明 |
✅ 使用 Pydantic 模型 | 提高类型安全,自动生成文档,便于复用 |
✅ 合理设置默认值 | 区分必填与可选参数,提升 API 友好性 |
✅ 添加参数约束 | 使用 |
✅ 保持路由简洁 | 避免在一个接口中混合过多参数类型 |
✅ 利用自动文档 |
|
✅ 统一错误处理 | 自定义异常处理器,返回结构化错误信息 |
✅ 异步处理 I/O | 文件读写、数据库操作使用 |
❌ 避免在请求体中传递 ID | ID 应通过路径参数传递,符合 REST 规范 |
十一、总结
FastAPI 提供了一套声明式、类型安全、高度自动化的请求处理机制,极大提升了开发效率与 API 质量。以下是核心请求处理方式的总结:
请求部分 | 处理方式 |
路径参数 |
|
查询参数 | 函数参数 + |
请求体 | Pydantic 模型 + |
Header |
|
Cookie |
|
文件上传 |
|
表单数据 |
|
原始请求 |
|
通过合理组合这些机制,你可以构建出功能强大、结构清晰、易于维护的现代 Web API。