← blog 技术原理与实践 · 2026-08-11

网络 API 接口协议详解:aiohttp、FastAPI 与 ASGI/WSGI

从 aiohttp 与 FastAPI 的本质差异出发,拆解 ASGI/WSGI 协议、Starlette 的分层关系,以及服务器-框架-协议之间的完整调用链路。

9 min read

先说结论

常被放在一起比较的 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 的对比

WSGIASGI
同步/异步同步(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 应用”的框架,只是站在不同层级、解决不同问题,设计哲学完全不同。

需要纠正两点:

  1. FastAPI 不是”中间件”。“框架”是承载整个 Web 应用的骨架;“中间件”(middleware)只是框架内部介于”收到请求”和”处理请求”之间的一小段钩子代码(日志、鉴权、CORS)。FastAPI 本身是一个完整的 Web 应用框架,中间件只是它内部的一个功能子集。打个比方:把 FastAPI 说成中间件,就像”用发动机的某个零件来指代整车”。
  2. aiohttp 也不是”更底层的 FastAPI”。它跟 FastAPI 解决的问题有重叠(都能处理 HTTP 请求),但设计哲学完全不同:aiohttp 是底层通用异步 HTTP 工具包,FastAPI 是类型驱动的生产级 Web 框架。

逐点深度对比

维度aiohttpFastAPI
本质HTTP 工具库(服务端+客户端)Web 应用框架(纯服务端)
底层原生 asyncioStarlette(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 则是建在这套链路之上的「现成厂房」,把收发之外的杂活全包了。选哪个,取决于你是想”自己造”还是”赶紧上线”。

Sources

No external sources for this entry.

Related