FastAPI教程-Starlette框架 作者:马育民 • 2026-08-15 14:07 • 阅读:10001 # 介绍 **FastAPI 底层 Web 框架就是 Starlette**,FastAPI 在 Starlette 之上增加了 Pydantic、路由参数解析、OpenAPI文档等能力。 FastAPI 的请求、响应、异常处理、中间件、后台任务全部来自 Starlette。 官方仓库:`https://github.com/encode/starlette` # Starlette & FastAPI关系 |功能|Starlette|FastAPI| |---|---|---| |ASGI底层、Request/Response、中间件、异常、websocket、后台任务|✅|✅(直接复用)| |路径/查询参数解析|❌|✅| |Pydantic请求体校验|❌|✅| |自动OpenAPI接口文档|❌|✅| FastAPI的 `app` 对象本质就是 `Starlette` 的子类。 ```python from fastapi import FastAPI print(issubclass(FastAPI, Starlette)) # True ``` # 一、定位 - Starlette:轻量异步 ASGI Web 框架,只做 Web 底层(路由、请求、响应、中间件、异常、生命周期)**不做参数校验、不做接口文档**。 - FastAPI = Starlette(web内核) + Pydantic(数据校验) + OpenAPI(接口文档)。 FastAPI 的 `Request`、`Response`、`JSONResponse`、`HTTPException`、`BackgroundTasks` 全部**导入自 starlette**,fastapi只是做了重新导出。 ```python # 等价 from fastapi import Request from starlette.requests import Request from fastapi.responses import JSONResponse from starlette.responses import JSONResponse from fastapi import HTTPException from starlette.exceptions import HTTPException ``` # 二、基础组件 ### 1. 最小 Starlette 程序 ```python import uvicorn from starlette.applications import Starlette from starlette.requests import Request from starlette.responses import JSONResponse from starlette.routing import Route async def homepage(request: Request): return JSONResponse({"msg":"hello starlette"}) routes = [ Route("/", homepage) ] app = Starlette(routes=routes) if __name__ == "__main__": uvicorn.run(app, host="127.0.0.1", port=8000) ``` ### 2. Request 对象(starlette.requests.Request) 常用属性 ```python request.method # GET POST request.url # URL对象 request.query_params # 查询参数,类字典 MultiDict request.path_params # 路径参数 request.headers # 请求头 MultiDict request.cookies # cookie await request.body() # raw bytes await request.json() # 解析json await request.form() # form表单 ``` > Request 是**ASGI scope + receive 封装**,`await request.json()`只能调用一次,body消费完就空。 ### 3. Response 系列(starlette.responses) - `Response(content, status_code, media_type)` 基础响应 - `JSONResponse(content)` json返回 - `PlainTextResponse()` 纯文本 - `HTMLResponse()` html - `RedirectResponse(url)` 重定向 - `FileResponse` 返回文件 - `StreamingResponse` 流式返回(大文件、sse) > 所有响应必须实现 `__call__(scope, receive, send)` ASGI协议。 # 三、Starlette 异常系统 ### starlette.exceptions.HTTPException ```python raise HTTPException(status_code=403, detail="禁止访问", headers={}) ``` #### 异常处理器 `add_exception_handler` FastAPI 的 `@app.exception_handler` 本质就是封装 `app.add_exception_handler()`。 原生 Starlette 写法: ```python from starlette.applications import Starlette from starlette.exceptions import HTTPException from starlette.requests import Request from starlette.responses import JSONResponse app = Starlette() async def handler_403(request: Request, exc: HTTPException): return JSONResponse({"code":403,"msg": exc.detail}, status_code=403) # 注册异常处理器 app.add_exception_handler(HTTPException, handler_403) ``` ### 底层逻辑 当路由内抛出异常,starlette 查找已注册异常处理器;找到就执行处理器返回Response;没有匹配就走内置默认处理器。 ### 重要 - 异常处理器**只在请求生命周期内生效** - BackgroundTasks、手动`asyncio.create_task()`抛出异常,脱离request scope,**不会触发异常处理器**,直接抛出到事件循环。 ### Starlette 默认内置异常处理器 - 404 Not Found:找不到路由 - 405 Method Not Allowed:方法不允许 这些都是 Starlette 自带,FastAPI直接继承。 # 四、中间件 Middleware Starlette中间件模型:ASGI包装器,接收 `(request, call_next)`。 FastAPI `@app.middleware("http")` 完全继承自 Starlette。 原生写法: ```python from starlette.middleware.base import BaseHTTPMiddleware class LogMiddleware(BaseHTTPMiddleware): async def dispatch(self, request, call_next): print(f"请求:{request.url}") response = await call_next(request) print(f"响应状态:{response.status_code}") return response app = Starlette( routes=routes, middleware=[ Middleware(LogMiddleware) ] ) ``` 两种中间件写法: 1. **BaseHTTPMiddleware**:面向对象,拿到Request/Response,简单常用 2. **原始ASGI中间件**:直接操作 scope, receive, send,性能最高,但繁琐 BaseHTTPMiddleware 有一个经典坑:**不能读取 request.body()**,会导致后续路由拿不到body数据。 # 五、BackgroundTasks 后台任务 `starlette.background.BackgroundTasks` FastAPI直接导出这个类。 ```python from starlette.background import BackgroundTasks tasks = BackgroundTasks() tasks.add_task(func, arg1, arg2) # 附加到response,response返回客户端后才执行任务 response.background = tasks ``` 关键点: 1. **是同步/普通async函数,不是asyncio任务**; 2. 在**响应发送给客户端之后才执行**; 3. 任务抛出异常 → **不会触发异常处理器**,直接打印栈,请求已经结束; 4. 只绑定在 Response 对象上生效。 > 注意区分: > - BackgroundTasks:starlette提供,请求结束后顺序执行; > - asyncio.create_task:创建真正asyncio任务,和请求生命周期无关。 # 六、生命周期 Lifespan Starlette 0.20+ 使用 lifespan 上下文管理器,取代旧的 `on_event("startup")` / `on_event("shutdown")`。 FastAPI同样支持。 ```python from contextlib import asynccontextmanager @asynccontextmanager async def lifespan(app: Starlette): # 启动时执行 print("应用启动,初始化数据库、redis连接池") yield # 关闭时执行 print("应用关闭,释放资源") app = Starlette(routes=routes, lifespan=lifespan) ``` > `@app.on_event("startup")` 在新版Starlette/FastAPI已经标记废弃,优先用 lifespan。 # 七、路由系统 Routing - `Route(path, endpoint)` 普通http路由 - `WebSocketRoute(path, endpoint)` websocket路由 - `Mount(path, app)` 挂载子ASGI应用(非常常用,静态文件、子应用) 示例挂载静态文件: ```python from starlette.staticfiles import StaticFiles routes = [ Route("/", homepage), Mount("/static", app=StaticFiles(directory="./static"), name="static") ] ``` 原文出处:/show_1GW3rn9pxtaS.html