Skip to content

http-client

每当使用一个新的 HTTP 客户端库时, 有以下几个问题需要考虑:

  1. 每个客户端实例可以允许同时存在多少个连接? 即并发连接数是多少?
  2. 每个客户端实例如何处理当前请求对应的连接?
  3. 每个客户端实例针对超过最大连接数后的新入请求, 会如何处理?
  4. 每个客户端实例如何处理系统代理?
  5. 每个客户端实例如何维护连接池里的连接?
  6. 其他注意事项

python-httpx

客户端连接并发数

每个客户端实例可以允许同时存在多少个连接? 即并发连接数是多少?

httpx 使用 httpx._config.DEFAULT_LIMITS 作为默认连接数参数.

该参数限制了最大连接数为 100, 并允许同时使用 keepalive 表示的连接数最大为 20.

连接分配规则

每个客户端实例如何处理当前请求对应的连接?

  • 根据每个请求的 scheme、host、port 三元组作为 origin.

  • 每个请求在首次进入处理逻辑时, 会先尝试释放空闲连接和过期连接

  • 尝试获取连接

    • 获取请求严格按照请求队列的顺序, 只有处于未获得连接的元素中处于队首, 才会继续获取连接

    • 优先在连接池中寻找origin 相同且处于空闲状态的连接.

    • 当未有符合的空闲状态连接且连接数未达到上限, 创建一个新的连接.

  • 连接数已满且不存在可复用的空闲连接时, 当前请求阻塞直到超时或存在其他已完成的响应为该请求分配连接并唤醒


请求数过多策略

每个客户端实例针对超过最大连接数后的新入请求, 会如何处理?

  • 排队等待
    • 没有可复用的 origin 相同的空闲连接对象
    • 当前连接数大于最大连接数
    • 超过等待时间(默认 5s)后抛出异常

请求系统代理

每个客户端实例如何处理系统代理?

httpx 默认会从系统环境变量中读取 httphttpsall 对应的变量值, 并实例化对应的 代理 transport 对象.

处理请求时, 会根据 host 信息, 优先加载 mount 中匹配的 transport 对象.

未匹配到对应的代理 transport 后, 才会使用默认的 transport 对象.


连接维护

每个客户端实例如何维护连接池里的连接?

  • 每次发起 http 请求时, 会先遍历连接池, 释放已过期和处于idle状态的连接, 再进行后续的请求处理.
  • 每次请求从连接池中寻找可复用连接时, 会从后向前寻找, 并在寻找到符合 origin 规则的连接后, 会将该连接移动到队首.
  • 每次新创建的连接, 都会被添加到连接池的队首.
  • 每当一次 request/response 结束, 会在请求队列中从前向后寻找未持有连接对象的实例, 并尝试分配连接

其他注意事项

  • httpx 对处于网络异常的请求, 在每次连接失败后, 会按指数退避机制, 等待从 0.5->1.0->2.0->4.0 的时间后重试, 知道连接获取成功或超时.
  • httpx 默认情况下, 对于从连接池获取连接、在真实网络中建立连接、每次基于网络连接的读写, 设置的超时时间分别都是 5 秒, 独立计算.
  • httpx 对于连接的过期时间是在每一次响应读取结束后, 如果存在 keepalive 设置, 即更新过期时间.
  • httpx 对于没有设置 keepalive 的连接, 连接处于空闲状态, 也认为已过期.