先说结论
常被放在一起比较的 aiohttp 和 FastAPI,其实站在两个完全不同的层面:aiohttp 是底层、通用的异步 HTTP 工具库,FastAPI 是基于 ASGI 的高层 Web 应用框架。最关键的事实依据是:aiohttp 和 Starlette 都是 ASGI 框架,它们才是真正同层级的对手;而 FastAPI 建立在 Starlette 之上,只是在此基础上加了一层”类型驱动”封装。
逐个概念拆开讲
aiohttp:底层异步 HTTP 工具包
aiohttp 一个库干两件事——既能当服务端(aiohttp.web),也能当客户端(aiohttp.ClientSession)。服务端代码长这样:
from aiohttp import web
async def hello(request):
name = request.query.get('name', 'world')
return web.Response(text=f"Hello, {name}")
app = web.Application()
app.router.add_get('/hello', hello) # 手动注册路由
web.run_app(app) # 自带一个服务器
关键特点:没有自动校验(参数类型、必填与否都要自己检查)、没有自动文档(不生成 Swagger)、没有依赖注入(数据库连接等要手动组织)、路由是手动注册(不像 FastAPI 靠装饰器 + 类型注解自动绑定)、自带服务器(热启动)。
客户端能力是它独有的优势,FastAPI 没有:
async with aiohttp.ClientSession() as session:
async with session.get('https://api.example.com/data') as resp:
data = await resp.json()
一句话评价:“给你一堆积木,怎么搭都行”——给你最大控制权,但校验、文档、序列化这些便利都要自己搭。
FastAPI:高层、生产级、类型驱动的框架
FastAPI 建立在 Starlette(一个 ASGI 框架)之上,加了一层”类型驱动的魔术”——只要写类型注解,就自动完成校验、文档、序列化、参数绑定:
from fastapi import FastAPI, Query
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str # 类型 = 校验规则
price: float
@app.get("/hello")
async def hello(name: str = Query(..., min_length=3)):
return {"message": f"Hello, {name}"}
@app.post("/items")
async def create_item(item: Item): # 请求体会被自动解析、校验
return {"saved": item}
FastAPI 自动帮你做的事:请求参数自动绑定(?name=xxx 自动进来,类型不对返回 422)、请求体自动校验(POST 的 JSON 自动解析成 Item 对象)、自动生成 OpenAPI 文档(访问 /docs 有 Swagger UI)、依赖注入(Depends())、支持同步 def(框架自动放到线程池,不用学 async 也能用)。
但 FastAPI 是纯服务端,没有内置 HTTP 客户端,要对外发请求得自己配 httpx 或 aiohttp。
一句话评价:“你只管描述数据长什么样,剩下(校验/文档/序列化/路由绑定)它全包了”。
ASGI 是什么:Python 异步 Web 的接口标准
ASGI(Asynchronous Server Gateway Interface) 是 Python 的异步 Web 服务器网关接口,是 WSGI 的异步继任者。它定义「Web 服务器」和「Python 应用」之间如何通信的标准协议/约定。任何实现了这套接口的服务器都能跑任何实现了这套接口的应用,互相解耦。
ASGI 应用的本质
一个 ASGI 应用本质上是一个可调用对象,接收三个参数:
async def app(scope, receive, send):
...
- scope:连接信息字典(method、path、headers、协议类型是 http 还是 websocket 等)
- receive:异步函数,用于接收来自客户端的事件(请求体、WebSocket 消息)
- send:异步函数,用于发送事件回客户端(响应头、响应体、WebSocket 消息)
这套「异步调用 + 事件流」的模型,让它能同时处理 HTTP 和需要双向通信的 WebSocket 等协议。
ASGI 与 WSGI 的对比
| WSGI | ASGI | |
|---|---|---|
| 同步/异步 | 同步(def) | 异步(async def) |
| 是否支持 WebSocket/长连接 | ❌ | ✅ |
| 是否支持后台任务/生命周期 | ❌ | ✅ |
| 高并发吞吐 | 受限于同步线程 | 基于事件循环,更高 |
WSGI 自 2003 年定义了 Python Web 的同步标准。随着 asyncio 普及和 WebSocket、HTTP/2、SSE(服务器推送)等需求出现,WSGI 无法胜任(它只能处理”请求→响应”这种同步模式),于是诞生了 ASGI。
典型生态
- 服务器(实现 ASGI server):Uvicorn、Daphne、Hypercorn
- 框架(实现 ASGI app):Starlette、FastAPI、Quart、Django(3.0+)
- 中间件:各种 ASGI 中间件,如认证、日志、CORS 等常见用途
回到”同层级”这句话
前面说的「FastAPI 和 aiohttp 同层级的对手其实是 Starlette」,原因就在这里——Starlette 和 aiohttp 都是 ASGI 框架,实现了同一套协议;而 FastAPI 是在 Starlette 之上做了一层”类型驱动”封装,所以 FastAPI 也是 ASGI 应用,能被 Uvicorn 跑起来。
实际运行链路
Nginx/Uvicorn(ASGI server) → ASGI 协议 → Starlette/FastAPI(ASGI app)
常见部署:生产环境用 Nginx 做反向代理,后面跑 Uvicorn,Uvicorn 通过 ASGI 协议把请求交给 FastAPI/Starlette 处理。
探索中有个容易走偏的概念
一开始容易把 FastAPI 理解成”连接网站客户端与 Python 应用的中间件”,方向对但措辞容易误导。这也是本主题想要保留的一条探索弯路及其修正:
来源纠正:它们都不是”中间件”,而是”连接 Web 客户端和 Python 应用”的框架,只是站在不同层级、解决不同问题,设计哲学完全不同。
需要纠正两点:
- FastAPI 不是”中间件”。“框架”是承载整个 Web 应用的骨架;“中间件”(middleware)只是框架内部介于”收到请求”和”处理请求”之间的一小段钩子代码(日志、鉴权、CORS)。FastAPI 本身是一个完整的 Web 应用框架,中间件只是它内部的一个功能子集。打个比方:把 FastAPI 说成中间件,就像”用发动机的某个零件来指代整车”。
- aiohttp 也不是”更底层的 FastAPI”。它跟 FastAPI 解决的问题有重叠(都能处理 HTTP 请求),但设计哲学完全不同:aiohttp 是底层通用异步 HTTP 工具包,FastAPI 是类型驱动的生产级 Web 框架。
逐点深度对比
| 维度 | aiohttp | FastAPI |
|---|---|---|
| 本质 | HTTP 工具库(服务端+客户端) | Web 应用框架(纯服务端) |
| 底层 | 原生 asyncio | Starlette(ASGI 框架)之上 |
| 热启动 | 自带服务器 | 需要单独跑 Uvicorn |
| 数据校验 | ❌ 自己写 | ✅ Pydantic 自动 |
| 自动文档 | ❌ | ✅ Swagger/ReDoc |
| 依赖注入 | ❌ 手动管理 | ✅ 内置 |
| HTTP 客户端 | ✅ 内置 | ❌ 需 httpx |
| WebSocket | ✅ | ✅ |
| 学习门槛 | 中(要自己造轮子) | 低(类型注解驱动) |
| 控制粒度 | 高(适合定制) | 中(框架替你做了决定) |
| 序列化 | 手动 json.dumps | 自动 dict/JSON |
补充层级关系:aiohttp 和 Starlette 同为 ASGI 框架,FastAPI 是在 Starlette 之上的”类型驱动封装层”,因此它俩才算同层级对手。
建立心智模型
aiohttp = 「引擎和零件」,FastAPI = 「整车」。
- aiohttp 给你原材料:一个能收发 HTTP 的异步引擎。造爬虫、造代理、造网关、造自定义协议层时最合适,因为它不绑定你的玩法。
- FastAPI 给你调试好的生产线:路由、校验、文档、序列化、依赖注入全配好。想快速上线标准 REST API,几乎零配置。
ASGI 可以理解成新一代 Python Web 的「USB 接口」标准,让服务器和应用能自由插拔组合。
一个小例子感受差距
需求:接收 GET /weather?city=北京,返回该城市天气。
aiohttp(全部手动):
from aiohttp import web
async def weather(request):
city = request.query.get('city')
if not city:
return web.json_response({'error': 'city is required'}, status=400)
return web.json_response({'city': city, 'temp': 25})
app = web.Application()
app.router.add_get('/weather', weather)
FastAPI(类型驱动):
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/weather")
async def weather(city: str = Query(..., min_length=2)):
return {"city": city, "temp": 25}
FastAPI 版本少写了参数校验、错误返回、路由注册方式,却多得到 /docs 自动文档、422 自动错误、类型安全。
一句话总结
- FastAPI:更贴近”生产脚手架”,靠类型提示自动完成校验、文档、序列化,适合快速开发 REST API。
- aiohttp:更接近”工具包”,给你更多底层控制权,适合写爬虫、网关、需要高度定制或同时做客户端/服务端的场景。
两库可以共存
来源明确说”两者其实不冲突”:可以在 FastAPI 应用里用 aiohttp.ClientSession 发起 HTTP 请求,各取所长。服务端用 FastAPI 的速度和类型安全,对外发请求用 aiohttp 的内置异步客户端。
补充示例(非来源原文,仅用于说明共存方式):下面用 FastAPI 搭服务、用 aiohttp 的客户端发外部请求。
from fastapi import FastAPI
import aiohttp
app = FastAPI()
@app.get("/fetch")
async def fetch_external():
async with aiohttp.ClientSession() as session:
async with session.get("https://api.example.com/data") as resp:
return await resp.json()
选型建议
- 需要快速搭建带文档、校验的 API → FastAPI,现代主流选择。
- 需要底层异步客户端、写爬虫、做代理,或对框架侵入性要求低 → aiohttp。
- 两者可以共存:用 FastAPI 搭服务,里面用
aiohttp.ClientSession去请求外部 API,取长补短。
如果想象力是「客户端 → 服务器 → Python 应用」,那 aiohttp 是这套链路里最底层的「HTTP 收发机器」(而且能当客户端),FastAPI 则是建在这套链路之上的「现成厂房」,把收发之外的杂活全包了。选哪个,取决于你是想”自己造”还是”赶紧上线”。