文章目录
- 前言
- 一、阶段学习目标
- 二、核心概念:什么是中间件
- 2\.1 执行流程
- 2\.2 两大中间件写法
- 2\.3 适用业务场景
- 三、实战 1:CORS 跨域配置(前后端分离必备)
- 3\.1 同源策略原理
- 3\.2 基础配置(开发环境)
- 3\.3 生产环境安全规范(避坑重点)
- 四、实战 2:自定义通用中间件
- 4\.1 简易装饰器中间件:请求耗时 \+ 日志
- 4\.2 进阶类中间件:全局 Request\-ID 链路追踪
- 4\.3 组合注册:统一在 core/middlewares 管理
- 五、实战 3:APIRouter 模块化拆分(大型项目核心)
- 5\.1 单业务路由示例 routers/\[user\.py\]\(user\.py\)
- 5\.2 路由聚合 routers/**init**\.py
- 5\.3 main 统一挂载
- 六、企业级大型标准项目分层架构
- 6\.1 完整目录(适配 SQLModel、JWT、中间件、迁移)
- 6\.2 各目录职责(分层核心意义:隔离变更)
- 6\.3 \[main\.py\]\(main\.py\) 统一初始化模板
- 七、阶段综合实战完整代码
- 八、新手高频避坑指南
- 九、阶段核心总结
前言
前面我们已经完成数据库、JWT 鉴权、依赖注入、CRUD 全套业务能力,但小型单文件代码无法支撑多人协作、大型后台项目。本阶段解决三大工程核心痛点:
跨域 CORS:前后端分离 Vue/React 前端请求接口 403 拦截,生产安全规范配置;
自定义中间件:全局请求日志、耗时统计、统一请求 ID、IP 拦截、全局校验;
大型分层架构:单文件拆分模块化
APIRouter、多版本 API、core 核心包规范,适配企业多人开发。
学习前置:已掌握 FastAPI 路由、依赖注入、SQLModel 数据库,本阶段完全贴合线上项目标准,1 天学完可直接搭建可维护大型后端骨架。
一、阶段学习目标
理解中间件执行流程:请求前置处理、响应后置处理;
掌握官方
CORSMiddleware跨域配置,区分开发 / 生产安全写法;编写通用异步中间件:请求耗时日志、全局请求 ID、客户端 IP 记录;
学会 Starlette 基类中间件,实现复杂拦截逻辑(黑白名单限流);
掌握
APIRouter模块化拆分,按业务拆分路由、统一版本前缀;企业标准分层目录:core 核心、api 路由、db 数据库、modules 业务隔离;
全局统一注册:中间件、异常、路由、数据库初始化集中管理;
多人协作项目规范:分层职责、代码解耦、变更隔离。
二、核心概念:什么是中间件
2.1 执行流程
所有 HTTP 请求都会先经过中间件,再进入路由函数;路由处理完成后,再次经过中间件返回响应。
执行顺序:
客户端请求 → 中间件前置逻辑 → 路由接口执行 → 中间件后置逻辑 → 返回前端
2.2 两大中间件写法
装饰器简易
@app.middleware("http"):快速实现轻量逻辑(日志、耗时);继承
BaseHTTPMiddleware类:适合复杂、可复用中间件(限流、黑白名单)。
2.3 适用业务场景
前后端跨域 CORS 处理;
全局请求日志、耗时监控;
生成全局 Request-ID,日志链路追踪;
黑白 IP 拦截、接口限流;
统一响应头添加、全局权限预检;
全局异常兜底补充处理。
三、实战 1:CORS 跨域配置(前后端分离必备)
3.1 同源策略原理
前端页面域名、端口、协议任意一项与后端不一致,浏览器触发跨域拦截,Vue/React 开发环境localhost:5173对接后端8000必出现跨域报错。
3.2 基础配置(开发环境)
fromfastapiimportFastAPIfromfastapi.middleware.corsimportCORSMiddleware app=FastAPI()# 允许的前端域名列表allow_origins=["http://localhost:5173","http://127.0.0.1:5173"]app.add_middleware(CORSMiddleware,allow_origins=allow_origins,# 允许来源allow_credentials=True,# 允许携带Cookie/Token凭证allow_methods=["*"],# 允许所有请求方法 GET/POST/PUT/DELETEallow_headers=["*"],# 允许所有请求头(Authorization)max_age=86400# 预检请求缓存1天,减少OPTIONS请求)3.3 生产环境安全规范(避坑重点)
❌ 禁止生产使用allow_origins=["*"]:通配符无法搭配allow_credentials=True,Token/Cookie 会失效,存在跨站风险。
✅ 生产从.env 读取域名配置,硬编码改为配置中心:
# config/settings.py 读取配置classGlobalSettings(BaseSettings):cors_origins:list[str]model_config=SettingsConfigDict(env_file=".env")# .envCORS_ORIGINS=http://xxx.com,https://admin.xxx.com# main.py 引入配置app.add_middleware(CORSMiddleware,allow_origins=settings.cors_origins,allow_credentials=True,allow_methods=["GET","POST","PUT","DELETE"],# 限制危险方法allow_headers=["Content-Type","Authorization"],# 仅开放必要请求头max_age=86400)四、实战 2:自定义通用中间件
4.1 简易装饰器中间件:请求耗时 + 日志
importtimefromfastapiimportRequest# 定义 HTTP 中间件,拦截并处理所有进入应用的 HTTP 请求@app.middleware("http")asyncdeflog_middleware(request:Request,call_next):# ========== 请求前置逻辑(在路由处理函数执行前运行) ==========# 记录请求开始的高精度时间,用于后续计算耗时start=time.perf_counter()# 提取并记录请求的基本信息client_ip=request.client.host# 获取客户端 IP 地址method=request.method# 获取 HTTP 请求方法(如 GET, POST)path=request.url.path# 获取请求的 URL 路径# 打印请求进入的日志信息print(f"【请求进入】{method}{path}客户端IP:{client_ip}")# 调用下一个中间件或路由处理函数,获取响应对象response=awaitcall_next(request)# ========== 响应后置逻辑(在路由处理函数执行后运行) ==========# 计算请求总耗时(毫秒),并保留两位小数cost=round((time.perf_counter()-start)*1000,2)# 在响应头中添加自定义字段,方便前端或监控系统获取接口性能数据response.headers["X-Request-Cost-ms"]=str(cost)# 打印请求处理完成的日志,包含状态码和耗时print(f"【请求结束】{method}{path}状态码:{response.status_code}耗时:{cost}ms")# 将修改后的响应对象返回给客户端returnresponse4.2 进阶类中间件:全局 Request-ID 链路追踪
importuuidfromstarlette.middleware.baseimportBaseHTTPMiddlewarefromstarlette.requestsimportRequestfromstarlette.responsesimportResponseclassRequestIdMiddleware(BaseHTTPMiddleware):asyncdefdispatch(self,request:Request,call_next)->Response:# 从请求头获取或生成新request-idreq_id=request.headers.get("X-Request-ID",str(uuid.uuid4())[:16])# 传递给后续所有日志、异常response=awaitcall_next(request)# 响应返回request-id,用于前后端排查问题response.headers["X-Request-ID"]=req_idreturnresponse# 注册中间件app.add_middleware(RequestIdMiddleware)4.3 组合注册:统一在 core/middlewares 管理
企业项目不建议写在 main,单独文件统一管理所有中间件,集中注册:
# core/middlewares.pyfromfastapi.middleware.corsimportCORSMiddlewaredefregister_middlewares(app:FastAPI,settings):# 1. CORS跨域app.add_middleware(CORSMiddleware,allow_origins=settings.cors_origins,allow_credentials=True,allow_methods=["*"],allow_headers=["*"],)# 2 请求ID中间件app.add_middleware(RequestIdMiddleware)# 3 日志耗时中间件(装饰器需封装函数注册)@app.middleware("http")asyncdeflog_mid(request,call_next):...五、实战 3:APIRouter 模块化拆分(大型项目核心)
单文件路由臃肿,使用APIRouter按业务拆分:用户、订单、管理员、公共接口,支持统一前缀、分组标签、模块专属依赖。
5.1 单业务路由示例 routers/[user.py](user.py)
fromfastapiimportAPIRouter,Dependsfromdependencies.authimportget_active_user# 独立路由,统一前缀、标签、模块登录依赖user_router=APIRouter(prefix="/users",tags=["用户管理"],dependencies=[Depends(get_active_user)]# 当前模块全部接口需要登录)@user_router.get("/me",summary="获取个人信息")defget_info():return{}5.2 路由聚合 routers/init.py
统一收集所有业务路由,方便 main 导入:
fromfastapiimportAPIRouterfromrouters.userimportuser_routerfromrouters.orderimportorder_routerfromrouters.authimportauth_router# v1版本总路由api_v1=APIRouter(prefix="/api/v1")api_v1.include_router(auth_router)api_v1.include_router(user_router)api_v1.include_router(order_router)5.3 main 统一挂载
fromroutersimportapi_v1 app.include_router(api_v1)六、企业级大型标准项目分层架构
6.1 完整目录(适配 SQLModel、JWT、中间件、迁移)
fastapi_big_project/ ├── .env # 环境变量配置 ├── alembic/ # 数据库迁移 ├── alembic.ini ├── requirements.txt ├── main.py # 程序入口、统一注册组件 ├── core/ # 全局核心(无业务) │ ├── __init__.py │ ├── config.py # pydantic-settings全局配置 │ ├── middlewares.py # CORS/日志/RequestID所有中间件 │ ├── exceptions.py # 全局异常捕获、统一返回 │ ├── logger.py # 日志格式化配置 │ └── dependencies.py # 全局公共依赖(分页、鉴权) ├── db/ # 数据库全局 │ ├── __init__.py │ └── session.py # engine、get_db会话依赖 ├── models/ # SQLModel数据库实体 │ ├── user.py │ └── order.py ├── schemas/ # DTO分层模型 │ ├── user_schema.py │ └── order_schema.py ├── crud/ # 通用CRUD+业务操作 │ ├── base.py │ ├── user_crud.py │ └── order_crud.py ├── routers/ # 模块化路由 │ ├── __init__.py # v1总路由聚合 │ ├── auth_router.py │ ├── user_router.py │ └── order_router.py └── utils/ # 工具函数(加密、JWT、日期) ├── __init__.py └── security.py6.2 各目录职责(分层核心意义:隔离变更)
| 目录 | 职责 | 修改影响范围 |
|---|---|---|
| core | 全局配置、中间件、异常、通用依赖 | 全项目生效,修改需全量测试 |
| db | 数据库引擎、会话 | 仅数据库连接逻辑 |
| models | 数据表实体 | 仅表结构,配合 Alembic 迁移 |
| schemas | 入参 / 返回 DTO | 接口入参、返回字段调整 |
| crud | 数据库业务逻辑 | 增删改查 SQL 逻辑 |
| routers | API 路由、接口参数 | 仅 URL、请求方式、入参 |
| utils | 通用工具函数 | 加密、时间、校验工具 |
6.3 [main.py](main.py) 统一初始化模板
所有中间件、异常、路由、数据库集中注册,入口极简干净:
fromfastapiimportFastAPIfromcore.configimportsettingsfromcore.middlewaresimportregister_middlewaresfromcore.exceptionsimportregister_exceptionfromdb.sessionimportenginefromsqlmodelimportSQLModelfromroutersimportapi_v1# 开发临时建表definit_tables():ifsettings.app_env=="dev":SQLModel.metadata.create_all(bind=engine)# 创建应用实例defcreate_app()->FastAPI:app=FastAPI(title="大型后台管理系统",version="1.0")# 1 注册中间件(CORS、日志)register_middlewares(app,settings)# 2 注册全局异常处理器register_exception(app)# 3 挂载路由app.include_router(api_v1)# 4 启动事件初始化数据库@app.on_event("startup")defstartup():init_tables()returnapp app=create()if__name__=="__main__":importuvicorn uvicorn.run("main:app",reload=True,host="0.0.0.0",port=8000)七、阶段综合实战完整代码
整合 CORS、请求日志中间件、模块化路由、分层目录入口:
# core/middlewares.pyimporttimeimportuuidfromfastapiimportFastAPI,Requestfromfastapi.middleware.corsimportCORSMiddlewarefromstarlette.middleware.baseimportBaseHTTPMiddlewareclassRequestIdMiddleware(BaseHTTPMiddleware):asyncdefdispatch(self,request,call_next):rid=request.headers.get("X-Request-ID",str(uuid.uuid4())[:12])resp=awaitcall_next(request)resp.headers["X-Request-ID"]=ridreturnrespdefregister_middlewares(app:FastAPI,settings):# CORSapp.add_middleware(CORSMiddleware,allow_origins=settings.cors_origins,allow_credentials=True,allow_methods=["*"],allow_headers=["*"],)# RequestIDapp.add_middleware(RequestIdMiddleware)# 耗时日志中间件@app.middleware("http")asyncdeflog_mid(req:Request,call_next):s=time.perf_counter()resp=awaitcall_next(req)ms=round((time.perf_counter()-s)*1000,2)resp.headers["X-Cost"]=str(ms)print(f"{req.method}{req.url.path}{resp.status_code}{ms}ms")returnresp八、新手高频避坑指南
❌ 生产
CORS使用allow_origins=["*"],携带 Token/Cookie 失效;❌ 所有路由写在 main,项目膨胀后无法维护;
❌ 中间件注册顺序混乱,CORS 放在日志中间件后面导致 OPTIONS 无跨域头;
❌ 中间件忘记
await call_next(request),请求卡死无响应;❌ 业务、配置、数据库代码全部混在同一文件,多人协作冲突严重;
❌ 中间件内读取请求 body 导致流消耗,后续接口拿不到参数;
✅ CORS 域名从环境变量读取,区分开发生产;
✅ 按业务拆分 APIRouter,统一版本前缀
/api/v1;✅ 中间件统一封装在 core,不在 main 堆代码;
✅ 分层严格遵守职责,数据库逻辑不写路由。
九、阶段核心总结
中间件:分装饰器简易版、类复杂版,前置拦截 + 后置统一处理;
CORS:前后端分离必备,开发通配,生产限定域名,禁止
["*"]搭配凭证;模块化路由:
APIRouter拆分业务,统一前缀、模块专属登录依赖;大型分层:core 核心、db 数据库、models 实体、schemas 入参、crud 业务、routers 接口完全解耦;
工程规范:main 仅做统一注册,所有全局组件集中初始化,业务代码隔离。