requestsaiohttp 都是 Python 中用于发起 HTTP 请求的流行库,但它们的设计哲学和适用场景截然不同。选择哪一个,取决于你的项目是否使用 异步(async/await)架构


🚦 一句话结论

项目类型推荐库
同步代码(Flask、Django、脚本)requests
异步代码(FastAPI、Starlette、Tornado、aiohttp 服务端)aiohttp

💡 关键区别

  • requests阻塞式(同步) 的 —— 发起请求会“卡住”当前线程直到响应返回。
  • aiohttp非阻塞式(异步) 的 —— 发起请求后可立即去做别的事,等响应回来再处理。

🔍 一、详细对比

特性requestsaiohttp
类型同步(Blocking)异步(Non-blocking, asyncio)
安装pip install requestspip install aiohttp
简单 GETrequests.get(url)await session.get(url)
性能(高并发)❌ 差(每个请求占一个线程)✅ 极好(单线程处理 thousands 并发)
内存占用高(线程开销)低(事件循环)
学习曲线⭐ 极低(像写伪代码)中(需理解 async/await)
客户端 + 服务端仅客户端✅ 客户端 + 服务端(可写 Web API)
WebSocket 支持❌(需其他库)✅ 原生支持
HTTP/2 支持⚠️ 需额外库(如 aiohttp-http2
典型用户脚本、爬虫、Django 后台任务FastAPI 微服务、实时应用、高并发网关

🧪 二、代码示例对比

场景:获取 3 个 URL 的内容

requests(同步,顺序执行)

import requests
import time

urls = ["https://httpbin.org/delay/1"] * 3

start = time.time()
for url in urls:
    resp = requests.get(url)
    print(resp.status_code)
end = time.time()

print(f"耗时: {end - start:.2f} 秒")  # ≈ 3.0 秒(串行)

aiohttp(异步,并发执行)

import aiohttp
import asyncio
import time

async def fetch(session, url):
    async with session.get(url) as resp:
        return resp.status

async def main():
    urls = ["https://httpbin.org/delay/1"] * 3
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        for r in results:
            print(r)

start = time.time()
asyncio.run(main())
end = time.time()

print(f"耗时: {end - start:.2f} 秒")  # ≈ 1.1 秒(并发)

🔥 结果:同样 3 个延迟 1 秒的请求,

  • requests3 秒(一个接一个)
  • aiohttp1 秒(同时发起)

⚠️ 三、重要注意事项

1. 不要在异步函数里用 requests

# ❌ 危险!会阻塞整个事件循环
@app.get("/bad")
async def bad_endpoint():
    data = requests.get("https://api.example.com")  # ← 阻塞!其他请求卡住
    return data.json()

✅ 正确做法:

# ✅ 使用 aiohttp
@app.get("/good")
async def good_endpoint():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.example.com") as resp:
            data = await resp.json()
    return data

如果必须用 requests(如调用不支持异步的 SDK),请用 loop.run_in_executor 包装:

from functools import partial
data = await loop.run_in_executor(None, partial(requests.get, url))

2. aiohttp 必须复用 ClientSession

# ❌ 错误:每次新建 session(浪费资源)
async def bad_fetch(url):
    async with aiohttp.ClientSession() as session:  # ← 每次都新建
        async with session.get(url) as resp:
            return await resp.text()

# ✅ 正确:全局或长期复用 session
session = aiohttp.ClientSession()

async def good_fetch(url):
    async with session.get(url) as resp:
        return await resp.text()

# 应用关闭时记得关闭 session
@app.on_event("shutdown")
async def shutdown():
    await session.close()
📌 最佳实践:在 FastAPI 中通过依赖项管理 session 生命周期。

3. 功能差异

功能requestsaiohttp
自动解压 gzip✅(默认开启)
Session Cookie 持久化✅(通过 CookieJar
文件上传files={'file': open(...)}data=aiohttp.FormData()
超时控制timeout=5timeout=aiohttp.ClientTimeout(total=5)
重试机制urllib3 或第三方需手动实现或用 tenacity

🛠 四、如何选择?

requests 如果:

  • 你写的是 脚本、爬虫、Django 后台任务
  • 项目是 纯同步(无 async/await
  • 追求 最简代码(一行搞定)

aiohttp 如果:

  • 你在用 FastAPI / Starlette / Sanic
  • 需要 高并发调用外部 API(如微服务通信)
  • 项目已基于 asyncio
  • 需要 WebSocket 客户端

🧩 五、FastAPI 中的最佳实践(使用 aiohttp)

# deps.py
from aiohttp import ClientSession
from fastapi import Depends

async def get_http_client():
    # 实际项目中建议用 lifespan 管理全局 session
    async with ClientSession() as session:
        yield session

# main.py
@app.get("/proxy")
async def proxy_data(http_client: ClientSession = Depends(get_http_client)):
    async with http_client.get("https://api.external.com/data") as resp:
        return await resp.json()

更高级:使用 lifespan 管理全局 session(避免每次请求新建):

from contextlib import asynccontextmanager

session: Optional[ClientSession] = None

@asynccontextmanager
async def lifespan(app: FastAPI):
    global session
    session = ClientSession()
    yield
    await session.close()

app = FastAPI(lifespan=lifespan)

📊 六、性能对比(理论)

并发数requests(线程池)aiohttp(单线程)
10
100内存飙升,上下文切换开销大依然流畅
1000+可能崩溃✅ 轻松应对
🌐 在 I/O 密集型场景(如 API 网关、聚合服务),aiohttp 性能优势巨大

✅ 总结

requestsaiohttp
定位同步 HTTP 客户端异步 HTTP 客户端 + 服务端
哲学“简单即美”“高并发、高性能”
生态通用、无处不在异步 Python 生态核心
你的项目Django / 脚本 → 选它FastAPI / 异步 → 必选它

如果你正在开发 FastAPI + Tortoise-ORM 项目(典型的异步栈),请坚定使用 aiohttp 作为 HTTP 客户端。而 requests 留给你的同步脚本或数据迁移工具。