标准答案
- 每个请求创建客户端会失去连接复用并增加 DNS、TCP 和 TLS 成本。
- 异步客户端必须在 shutdown 关闭,阻塞客户端不能直接放进事件循环。
- 超时要区分连接、读取、写入和总 deadline,响应体要消费或关闭。
- 连接池和重试服从下游容量,重复 POST 必须有幂等协议。
题目解析
requests.Session 和 httpx.Client 可以复用连接池,减少 DNS、TCP 和 TLS 握手;httpx.AsyncClient 则把连接复用放在异步生命周期中。客户端应在应用启动或依赖注入容器中创建,在应用关闭时显式关闭,不能把释放责任交给垃圾回收。
超时至少要覆盖连接、写入、读取和总请求 deadline,响应体要被完整消费或关闭,否则连接无法回收到池中。异步 handler 直接调用 requests 会阻塞事件循环;同步代码如果无法替换,应放到有界执行器,同时把取消无法中断这一事实纳入设计。
重试必须根据方法和错误类型判断。连接失败或明确的 503 可能适合有限重试,但带副作用的 POST 需要幂等键或业务去重;多层客户端、网关和任务队列同时重试会把一次故障放大成请求风暴。
常见误区
- 误区:每次请求都创建 Client 或 Session。改正:按应用或任务作用域复用客户端,并在 shutdown 阶段关闭。
- 误区:AsyncClient 没有显式关闭。改正:使用应用生命周期钩子或 async with 管理它的生命周期。
- 误区:每一层都配置自己的自动重试。改正:确定唯一的重试责任层,使用总 deadline、退避和幂等边界。