(十九)用异步客户端完成真实网络等待
1. 在一个客户端范围内复用连接
HTTPX 提供异步 HTTP 接口,AsyncClient 管理连接与请求。一个客户端供一批请求共同使用,结束时再关闭:
# 项目文件:demos/httpx_async.py
# get 的网络等待交给事件循环;响应读完后 json() 是普通解析调用,不需要 await。
import asyncio
import httpx
from labserver import running_server
async def read_all(base_url):
async with httpx.AsyncClient(
base_url=base_url, timeout=1, trust_env=False
) as client:
async with asyncio.TaskGroup() as group:
tasks = [
group.create_task(
client.get(f"/api/books/{number}", params={"delay": 0.02})
)
for number in [1, 2, 3]
]
records = []
for task in tasks:
response = task.result()
response.raise_for_status()
records.append(response.json())
return [record["title"] for record in records]
if __name__ == "__main__":
with running_server() as server:
print(asyncio.run(read_all(server.base_url)))输出三本书名,按任务列表的输入次序排列。base_url 保存共同的地址前缀,params 编码查询,timeout 设置网络等待,trust_env=False 让本机练习直接连接目标,不读取代理等环境配置。异步客户端用 async with 关闭连接池。
await client.get 等待请求与正文读取;response.json() 继续执行同步 JSON 解析。raise_for_status() 把错误状态转换成 HTTPX 的 HTTPStatusError。它要放在希望失败被处理的位置:上例在请求组完成后逐项检查,后面的完整项目会在每个任务里检查,让失败立即传回任务组。HTTPX 异步支持
2. 把连接限制与操作限制分开
客户端连接池的 Limits(max_connections=2) 限制连接数量;信号量可以覆盖完整的一段“请求、读取、解析”等操作。工作任务拿到信号量后,仍可能等待可用连接,它们控制的资源不是同一个概念。HTTPX 连接限制
HTTPX 的超时分别观察 connect、read、write、pool 等等待:连接、接收下一批数据、发送数据,以及等待池中连接。它们不等于整批任务的总时长;外层再用 asyncio.timeout 安排总预算。HTTPX 超时
请求错误在 RequestError 类别下,例如连接失败、读取超时;错误状态由 raise_for_status 形成 HTTPStatusError;正文 JSON 与书籍字段又是之后的解析与校验。第六章按失败动作保留信息的方法在这里继续使用。HTTPX 错误类别