必须用 async with aiohttp.clientsession() 管理会话生命周期,显式设置 timeout 防止协程挂起,post json 用 json= 参数而非 data+headers,限制并发数避免连接耗尽或 429 错误。

async with aiohttp.ClientSession() 必须用,不能只写 await session.get()
直接 await session.get("https://example.com") 会报 RuntimeError: Session is closed —— 因为 aiohttp.ClientSession 不是“即用即弃”的工具,它管理连接池、Cookie、DNS 缓存等资源,必须用 async with 确保正确生命周期。不用上下文管理器,连接可能泄漏,短时间高频请求后出现 Too many open files 或连接超时。
- 错误写法:
session = aiohttp.ClientSession(); await session.get(...); await session.close()(手动 close 容易遗漏或抛异常中断) - 正确写法:
async with aiohttp.ClientSession() as session: await session.get(...) - 如果要复用 session(比如多个请求),把它作为参数传入协程,或放在类实例中,但别在函数里反复创建/关闭
timeout 参数不设就等于没设,aiohttp 默认不超时
aiohttp 的 ClientTimeout 默认是 None,意味着 DNS 查询、TCP 握手、TLS 握手、首字节等待、整个响应读取……全都不设限。线上服务一旦上游卡住,你的协程就永远挂起,拖垮整个 asyncio event loop。
- 必须显式配置:
timeout=aiohttp.ClientTimeout(total=10, connect=3, sock_read=5) -
total是总上限,其他子项不能超过它;connect控制建连阶段(含 DNS),sock_read控制从 socket 读响应体的时间 - 注意:如果用
raise_for_status=True,HTTP 4xx/5xx 错误仍会抛异常,但超时是独立机制,二者不冲突
POST 发 JSON 数据,别手动 json.dumps + headers,用 json= 参数
写 session.post(url, data=json.dumps({...}), headers={"Content-Type": "application/json"}) 看似没问题,实则埋雷:手动序列化可能忽略 ensure_ascii=False 导致中文乱码;headers 写错大小写或漏掉 charset;更严重的是,data= 会绕过 aiohttp 对 JSON 的自动编码和 content-type 设置逻辑,某些服务器(尤其 FastAPI/Starlette)会拒绝解析。
- 正确做法:
await session.post(url, json={"key": "中文值"})——aiohttp自动处理编码、header、content-type - 如果需要控制 JSON 序列化选项(如
default函数),得自己构造json.dumps(...),但此时必须配data=+ 手动 header,且确保Content-Type是application/json; charset=utf-8 -
json=和data=互斥,同时传会报ValueError
并发请求数量失控导致 ConnectionRefusedError 或 429
asyncio.gather(*[session.get(...) for _ in range(1000)]) 看起来高效,实际会让 aiohttp 在默认配置下瞬间发起上千 TCP 连接,远超系统文件描述符限制或目标服务器承受能力,结果不是本地报 [Errno 24] Too many open files,就是对方返回 429 Too Many Requests 或直接 ConnectionRefusedError。
立即学习“Python免费学习笔记(深入)”;
- 限制并发数:用
asyncio.Semaphore(10)包裹请求逻辑,确保最多 10 个并发 - ClientSession 默认启用连接池(
connector=aiohttp.TCPConnector(limit=100, limit_per_host=30)),但这个 limit 是“最大空闲连接数”,不是并发请求数,别混淆 - 对同一 host 大量请求,建议调高
limit_per_host,否则可能因连接复用不足反复建连
netstat -an | grep :443 | wc -l)、timeouts 日志、以及是否出现 Unclosed client session 警告。










