当前位置: 首页 > news >正文

【框架篇二】FastAPI路由与请求处理

目录

一、FastAPI架构与工作原理

1.1 核心组件

1.2 流程图

1.3 路由定义

二、参数处理的完整体系

2.1 参数类型图

2.2 路径参数用法

2.3 查询参数用法

2.4 请求体处理实例

三、响应处理与数据序列化

3.1 流程图

3.2 设计原则

3.3 HTTP状态码

3.3.1 成功 (2xx)

3.3.2 重定向 (3xx)

3.3.3 客户端错误 (4xx)

3.3.4 服务器错误 (5xx)

四、文件处理

4.1 流程图

4.2 文件上传实现

总结

路由系统就像是Web应用的"神经网络",决定了当用户发送不同的HTTP请求时,应用程序如何响应和处理。FastAPI的路由系统不仅功能强大,还具有出色的性能和开发体验。让我们一起深入了解这个现代Python Web开发的核心组件。

一、FastAPI架构与工作原理

FastAPI的路由系统建立在Starlette框架之上,采用了基于 装饰器 的声明式路由定义方式。这种设计让代码更加直观和易于维护,同时保持了高性能的特性。

1.1 核心组件

FastAPI的路由系统由几个核心组件构成:

路由装饰器:如@app.get()@app.post()等。这些装饰器不仅定义了HTTP方法,还可以指定路径、响应模型、状态码等多种参数。

路径操作函数:被装饰器修饰的Python函数,负责处理具体的业务逻辑。FastAPI会自动解析函数签名,提取参数信息,并进行类型验证。

路由表:FastAPI内部维护的路由映射表,记录了URL模式与处理函数的对应关系。当请求到来时,FastAPI会遍历这个表找到匹配的路由。

参数解析器:负责从HTTP请求中提取各种参数,包括路径参数、查询参数、请求头、请求体等,并根据类型注解进行自动转换和验证。

1.2 流程图

1.3 路由定义

from fastapi import FastAPI
from typing import Optionalapp = FastAPI(title="现代Web API", version="1.0.0")# 最简单的GET路由
@app.get("/")
def read_root():"""根路径,返回欢迎信息"""return {"message": "欢迎使用FastAPI", "version": "1.0.0"}# 带路径参数的路由
@app.get("/users/{user_id}")
def get_user(user_id: int):"""根据用户ID获取用户信息"""return {"user_id": user_id,"name": f"用户{user_id}","status": "active"}# 支持多种HTTP方法
@app.post("/users/")
def create_user():return {"message": "用户创建成功"}@app.put("/users/{user_id}")
def update_user(user_id: int):return {"message": f"用户{user_id}更新成功"}@app.delete("/users/{user_id}")
def delete_user(user_id: int):return {"message": f"用户{user_id}删除成功"}

FastAPI的路由系统具有以下显著优势:

自动类型转换:当你在函数参数中指定类型注解时,FastAPI会自动进行类型转换。如果转换失败,会返回详细的错误信息。

路径优先级:FastAPI按照路由定义的顺序进行匹配,更具体的路径应该定义在更通用的路径之前。

自动文档生成:每个路由都会自动出现在Swagger UI文档中,包括参数说明、响应格式等信息。

二、参数处理的完整体系

FastAPI提供了一套完整的参数处理体系,能够优雅地处理Web开发中遇到的各种参数类型。这个体系不仅功能强大,还具有出色的开发体验和类型安全性。

2.1 参数类型图

2.2 路径参数用法

路径参数是URL路径的一部分,它们为API提供了动态性和灵活性。FastAPI的路径参数支持多种数据类型和验证规则。

from fastapi import Path
from enum import Enum# 枚举类型的路径参数
class ItemType(str, Enum):electronics = "electronics"clothing = "clothing"books = "books"@app.get("/items/{item_type}/{item_id}")
def get_item(item_type: ItemType,item_id: int = Path(..., gt=0, description="商品ID,必须大于0")
):"""获取特定类型的商品信息- item_type: 商品类型,只能是 electronics, clothing, books 之一- item_id: 商品ID,必须是正整数"""return {"item_type": item_type,"item_id": item_id,"message": f"获取{item_type.value}类型的第{item_id}号商品"}# 复杂路径参数验证
@app.get("/users/{user_id}/posts/{post_id}")
def get_user_post(user_id: int = Path(..., ge=1, le=999999, description="用户ID"),post_id: int = Path(..., ge=1, description="文章ID")
):"""获取用户的特定文章"""return {"user_id": user_id,"post_id": post_id,"title": f"用户{user_id}的第{post_id}篇文章","content": "这里是文章内容..."}

2.3 查询参数用法

查询参数提供了丰富的过滤和配置选项,是构建灵活API的重要工具。

from fastapi import Query
from typing import List, Optional
from datetime import datetime@app.get("/search/")
def search_items(q: Optional[str] = Query(None, min_length=1, max_length=50, description="搜索关键词"),category: Optional[str] = Query(None, regex="^[a-zA-Z]+$", description="商品类别"),tags: List[str] = Query([], description="标签列表"),min_price: Optional[float] = Query(None, ge=0, description="最低价格"),max_price: Optional[float] = Query(None, ge=0, description="最高价格"),limit: int = Query(10, ge=1, le=100, description="返回结果数量"),offset: int = Query(0, ge=0, description="跳过的结果数量"),sort_by: Optional[str] = Query("created_at", regex="^(name|price|created_at)$"),order: Optional[str] = Query("desc", regex="^(asc|desc)$")
):"""高级商品搜索API支持多种过滤条件:- 关键词搜索- 类别筛选- 标签过滤- 价格区间- 分页和排序"""# 构建搜索条件filters = {}if q:filters["keyword"] = qif category:filters["category"] = categoryif tags:filters["tags"] = tagsif min_price is not None:filters["min_price"] = min_priceif max_price is not None:filters["max_price"] = max_pricereturn {"filters": filters,"pagination": {"limit": limit, "offset": offset},"sorting": {"sort_by": sort_by, "order": order},"results": f"模拟搜索结果,共找到 {limit} 条记录"}

2.4 请求体处理实例

请求体是POST、PUT等请求传递复杂数据的主要方式。FastAPI结合Pydantic提供了强大的请求体处理能力。

from pydantic import BaseModel, Field, EmailStr, validator
from typing import Optional, List
from datetime import datetimeclass Address(BaseModel):"""地址信息模型"""street: str = Field(..., min_length=1, max_length=100)city: str = Field(..., min_length=1, max_length=50)country: str = Field(..., min_length=2, max_length=50)postal_code: str = Field(..., regex=r"^\d{6}$")class UserCreate(BaseModel):"""用户创建模型"""username: str = Field(..., min_length=3, max_length=20, regex="^[a-zA-Z0-9_]+$")email: EmailStrpassword: str = Field(..., min_length=8, max_length=100)full_name: Optional[str] = Field(None, max_length=50)age: Optional[int] = Field(None, ge=13, le=120)interests: List[str] = Field(default_factory=list, max_items=10)address: Optional[Address] = Noneis_active: bool = True@validator('password')def validate_password(cls, v):"""密码强度验证"""if not any(c.isupper() for c in v):raise ValueError('密码必须包含至少一个大写字母')if not any(c.islower() for c in v):raise ValueError('密码必须包含至少一个小写字母')if not any(c.isdigit() for c in v):raise ValueError('密码必须包含至少一个数字')return v@validator('interests')def validate_interests(cls, v):"""兴趣爱好验证"""if len(v) != len(set(v)):raise ValueError('兴趣爱好不能重复')return v@app.post("/users/")
def create_user(user: UserCreate):"""创建新用户支持完整的用户信息,包括:- 基本信息验证- 密码强度检查- 地址信息- 兴趣爱好管理"""return {"message": "用户创建成功","user_id": 12345,"username": user.username,"created_at": datetime.now().isoformat()}

三、响应处理与数据序列化

响应处理是API开发中的关键环节,决定了客户端接收到的数据格式和结构。FastAPI提供了灵活而强大的响应处理机制,能够满足各种复杂的业务需求。

3.1 流程图

3.2 设计原则

响应模型不仅定义了API的输出格式,还为自动文档生成提供了重要信息。设计良好的响应模型能够提高API的可维护性和用户体验。

from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import datetime
from enum import Enumclass UserStatus(str, Enum):"""用户状态枚举"""active = "active"inactive = "inactive"suspended = "suspended"class UserProfile(BaseModel):"""用户档案响应模型"""id: int = Field(..., description="用户唯一标识")username: str = Field(..., description="用户名")email: str = Field(..., description="邮箱地址")full_name: Optional[str] = Field(None, description="真实姓名")status: UserStatus = Field(..., description="用户状态")created_at: datetime = Field(..., description="创建时间")last_login: Optional[datetime] = Field(None, description="最后登录时间")profile_image: Optional[str] = Field(None, description="头像URL")class Config:# 配置示例数据,用于API文档展示schema_extra = {"example": {"id": 1,"username": "john_doe","email": "john@example.com","full_name": "John Doe","status": "active","created_at": "2024-01-01T00:00:00","last_login": "2024-01-15T10:30:00","profile_image": "https://example.com/avatar.jpg"}}class PaginatedResponse(BaseModel):"""分页响应基础模型"""total: int = Field(..., description="总记录数")page: int = Field(..., description="当前页码")size: int = Field(..., description="每页大小")pages: int = Field(..., description="总页数")class UserListResponse(PaginatedResponse):"""用户列表响应模型"""users: List[UserProfile] = Field(..., description="用户列表")@app.get("/users/{user_id}", response_model=UserProfile)
def get_user(user_id: int):"""获取用户详细信息"""# 模拟数据库查询user_data = {"id": user_id,"username": f"user_{user_id}","email": f"user{user_id}@example.com","full_name": f"用户 {user_id}","status": UserStatus.active,"created_at": datetime.now(),"last_login": datetime.now(),"profile_image": f"https://example.com/avatar_{user_id}.jpg"}return UserProfile(**user_data)@app.get("/users/", response_model=UserListResponse)
def get_users(page: int = 1, size: int = 10):"""获取用户列表(分页)"""# 模拟分页数据total_users = 100total_pages = (total_users + size - 1) // sizeusers = []start_id = (page - 1) * size + 1for i in range(size):user_id = start_id + iif user_id <= total_users:users.append(UserProfile(id=user_id,username=f"user_{user_id}",email=f"user{user_id}@example.com",full_name=f"用户 {user_id}",status=UserStatus.active,created_at=datetime.now(),last_login=datetime.now()))return UserListResponse(total=total_users,page=page,size=size,pages=total_pages,users=users)

3.3 HTTP状态码

HTTP状态码是RESTful API设计的重要组成部分,正确使用状态码能够让API更加专业和易于理解。

3.3.1 成功 (2xx)
状态码名称描述使用场景FastAPI示例
200OK请求成功GET、PUT、PATCH请求成功@app.get("/users/")
201Created资源创建成功POST请求成功创建资源@app.post("/users/", status_code=201)
202Accepted请求已接受,但处理未完成异步处理任务文件上传、批量处理
204No Content请求成功但无返回内容DELETE请求成功@app.delete("/users/{id}", status_code=204)
3.3.2 重定向 (3xx)
状态码名称描述使用场景FastAPI示例
301Moved Permanently永久重定向URL结构调整RedirectResponse(url="/new-url", status_code=301)
302Found临时重定向临时页面跳转RedirectResponse(url="/temp-url", status_code=302)
304Not Modified资源未修改缓存验证配合ETag使用
3.3.3 客户端错误 (4xx)
状态码名称描述使用场景FastAPI示例
400Bad Request请求格式错误参数验证失败HTTPException(status_code=400, detail="参数错误")
401Unauthorized未认证需要登录HTTPException(status_code=401, detail="请先登录")
403Forbidden已认证但无权限权限不足HTTPException(status_code=403, detail="权限不足")
404Not Found资源不存在找不到指定资源HTTPException(status_code=404, detail="用户不存在")
405Method Not AllowedHTTP方法不允许使用了不支持的方法FastAPI自动处理
409Conflict资源冲突数据冲突(如重复创建)HTTPException(status_code=409, detail="用户名已存在")
410Gone资源已永久删除资源已被删除且不会恢复已删除的文章、用户
413Payload Too Large请求体过大文件上传超限HTTPException(status_code=413, detail="文件过大")
415Unsupported Media Type不支持的媒体类型文件格式不支持HTTPException(status_code=415, detail="不支持的文件格式")
422Unprocessable Entity请求格式正确但语义错误Pydantic验证失败FastAPI自动处理
429Too Many Requests请求过于频繁触发限流HTTPException(status_code=429, detail="请求过于频繁")
3.3.4 服务器错误 (5xx)
状态码名称描述使用场景FastAPI示例
500Internal Server Error服务器内部错误未处理的异常HTTPException(status_code=500, detail="服务器错误")
501Not Implemented功能未实现API功能开发中HTTPException(status_code=501, detail="功能开发中")
502Bad Gateway网关错误上游服务异常数据库连接失败
503Service Unavailable服务不可用服务维护中HTTPException(status_code=503, detail="服务维护中")
504Gateway Timeout网关超时上游服务响应超时第三方API调用超时
from fastapi import HTTPException, status
from fastapi.responses import JSONResponseclass APIResponse(BaseModel):"""统一API响应格式"""success: bool = Field(..., description="请求是否成功")message: str = Field(..., description="响应消息")data: Optional[dict] = Field(None, description="响应数据")error_code: Optional[str] = Field(None, description="错误代码")@app.post("/users/", status_code=status.HTTP_201_CREATED, response_model=APIResponse)
def create_user(user: UserCreate):"""创建用户 - 201 Created"""try:# 模拟用户创建逻辑new_user_id = 12345return APIResponse(success=True,message="用户创建成功",data={"user_id": new_user_id, "username": user.username})except Exception as e:raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,detail="用户创建失败")@app.get("/users/{user_id}", response_model=APIResponse)
def get_user_with_error_handling(user_id: int):"""获取用户 - 包含错误处理"""if user_id < 1:raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,detail="用户ID必须大于0")# 模拟用户不存在的情况if user_id > 1000:raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,detail=f"用户 {user_id} 不存在")# 模拟权限不足的情况if user_id == 999:raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,detail="没有权限访问此用户信息")return APIResponse(success=True,message="获取用户信息成功",data={"user_id": user_id,"username": f"user_{user_id}","email": f"user{user_id}@example.com"})@app.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_user(user_id: int):"""删除用户 - 204 No Content"""if user_id < 1:raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,detail="无效的用户ID")# 模拟删除逻辑# 204状态码表示成功但不返回内容return None

四、文件处理

现代Web应用经常需要处理文件上传、下载和多媒体内容。FastAPI提供了完整的文件处理解决方案,支持单文件、多文件上传,以及各种文件类型的处理。

4.1 流程图

4.2 文件上传实现

文件上传是Web应用的常见需求,FastAPI提供了灵活的文件上传处理机制。

from fastapi import File, UploadFile, Form, HTTPException
from fastapi.responses import FileResponse
from typing import List, Optional
import os
import uuid
import mimetypes
from pathlib import Path# 配置文件上传参数
UPLOAD_DIR = Path("/tmp/uploads")
UPLOAD_DIR.mkdir(exist_ok=True)
MAX_FILE_SIZE = 10 * 1024 * 1024  # 10MB
ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif', '.pdf', '.doc', '.docx', '.txt'}
ALLOWED_MIME_TYPES = {'image/jpeg', 'image/png', 'image/gif','application/pdf', 'application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document','text/plain'
}class FileUploadResponse(BaseModel):"""文件上传响应模型"""filename: str = Field(..., description="原始文件名")saved_filename: str = Field(..., description="保存的文件名")file_size: int = Field(..., description="文件大小(字节)")content_type: str = Field(..., description="文件MIME类型")upload_time: datetime = Field(..., description="上传时间")file_url: str = Field(..., description="文件访问URL")def validate_file(file: UploadFile) -> None:"""文件验证函数"""# 检查文件扩展名file_ext = Path(file.filename).suffix.lower()if file_ext not in ALLOWED_EXTENSIONS:raise HTTPException(status_code=415,detail=f"不支持的文件类型: {file_ext}。支持的类型: {', '.join(ALLOWED_EXTENSIONS)}")# 检查MIME类型if file.content_type not in ALLOWED_MIME_TYPES:raise HTTPException(status_code=415,detail=f"不支持的MIME类型: {file.content_type}")@app.post("/upload/single/", response_model=FileUploadResponse)
async def upload_single_file(file: UploadFile = File(..., description="要上传的文件"),description: Optional[str] = Form(None, description="文件描述")
):"""单文件上传接口支持功能:- 文件类型验证- 文件大小限制- 安全文件名生成- 文件元数据记录"""# 验证文件validate_file(file)# 读取文件内容并检查大小content = await file.read()if len(content) > MAX_FILE_SIZE:raise HTTPException(status_code=413,detail=f"文件过大。最大允许大小: {MAX_FILE_SIZE // (1024*1024)}MB")# 生成安全的文件名file_ext = Path(file.filename).suffixsafe_filename = f"{uuid.uuid4()}{file_ext}"file_path = UPLOAD_DIR / safe_filename# 保存文件with open(file_path, "wb") as f:f.write(content)# 返回上传结果return FileUploadResponse(filename=file.filename,saved_filename=safe_filename,file_size=len(content),content_type=file.content_type,upload_time=datetime.now(),file_url=f"/files/{safe_filename}")@app.post("/upload/multiple/")
async def upload_multiple_files(files: List[UploadFile] = File(..., description="要上传的文件列表"),category: str = Form(..., description="文件分类")
):"""多文件上传接口支持批量上传多个文件,并进行统一管理"""if len(files) > 10:raise HTTPException(status_code=400,detail="一次最多只能上传10个文件")upload_results = []total_size = 0for file in files:# 验证每个文件validate_file(file)# 读取文件内容content = await file.read()file_size = len(content)total_size += file_size# 检查单个文件大小if file_size > MAX_FILE_SIZE:raise HTTPException(status_code=413,detail=f"文件 {file.filename} 过大")# 生成文件名并保存file_ext = Path(file.filename).suffixsafe_filename = f"{uuid.uuid4()}{file_ext}"file_path = UPLOAD_DIR / safe_filenamewith open(file_path, "wb") as f:f.write(content)upload_results.append({"original_name": file.filename,"saved_name": safe_filename,"size": file_size,"content_type": file.content_type,"url": f"/files/{safe_filename}"})return {"message": f"成功上传 {len(files)} 个文件","category": category,"total_size": total_size,"files": upload_results}

总结

通过本文的探讨,我们了解了FastAPI路由与请求处理的核心机制。

关键要点回顾:

  1. 路由系统:基于装饰器的声明式设计,支持自动类型转换和验证
  2. 参数处理:完整的参数体系,包括路径参数、查询参数、请求体等
  3. 响应处理:灵活的响应模型和状态码管理
  4. 文件处理:完善的文件上传下载机制
  5. 架构设计:模块化的路由组织和高级特性
 

http://www.xdnf.cn/news/1341289.html

相关文章:

  • Linux 网络命令大全
  • uniapp 自定义组件封装、easycom匹配规则
  • 2025-08-21 Python进阶4——错误和异常
  • 用 Python 写的自动化测试 WPF 程序的一个案例
  • 【GaussDB】使用gdb定位GaussDB编译package报错
  • Spring Boot整合Amazon SNS实战:邮件订阅通知系统开发
  • 第三阶段数据库-6:sql中函数,多表查询,运算符,索引,约束
  • 我从零开始学微积分(2)- 函数与图形
  • 与森马品牌代言人王安宇专注日常力量,再启新常服故事
  • Qt二维码生成器项目开发教程 - 从零开始构建专业级QR码生成工具
  • 精算中的提升曲线(Lift Curve)与机器学习中的差别
  • Design Compiler:逻辑库名与逻辑库文件名及其指定方式
  • 交易高光时刻-01
  • langgraph快速搭建agent后端和react前端
  • springboot 启动后get请求任意接口地址会跳到登录页
  • 【TrOCR】模型预训练权重各个文件解读
  • 【Java集合】List,Map,Set-详细讲解
  • ODDR实现多bit单边沿采样数据转为多bit双沿采样数据
  • 效率跃迁 ,亚数TrustAsia 加速证书管理迈向 CaaS 新阶段
  • 意象驱动的深层语义:感知认知统一对自然语言处理与知识图谱的影响
  • 活性数据处理与标准化
  • 在互联网大厂的Java面试:谢飞机的搞笑历险记
  • 学习 k 均值聚类算法的心得
  • 2025-08-21 Python进阶8——命名空间作用域
  • gRPC 与 HTTP 性能对比分析
  • 微算法科技(NASDAQ:MLGO)构建去中性化区块链预言机,实现跨链信息互通
  • 使用 X11 转发服务器界面
  • 整体设计 之定稿 “凝聚式中心点”原型 --整除:智能合约和DBMS的在表层挂接 能/所 依据的深层套接 之2
  • 迅为R3568开发板OpeHarmony学习开发手册-配置远程访问环境
  • Typescript入门-函数讲解