Skip to content

Requests 兼容性指南

HTTPX 旨在与 requests API 广泛兼容,但在某些地方存在一些设计差异。

本文档概述了 API 存在差异的地方...

重定向

requests 不同,HTTPX 默认不跟随重定向

我们在此处的行为有所不同,因为自动重定向很容易掩盖不必要的网络调用

您仍然可以启用自动跟随重定向的行为,但需要显式指定...

response = client.get(url, follow_redirects=True)

或者实例化一个默认启用重定向跟随的客户端...

client = httpx.Client(follow_redirects=True)

客户端实例

HTTPX 中与 requests.Session 对等的是 httpx.Client

session = requests.Session(**kwargs)

通常等同于

client = httpx.Client(**kwargs)

请求 URL

访问 response.url 将返回一个 URL 实例,而不是字符串。

如果需要字符串实例,请使用 str(response.url)

确定下一个重定向请求

requests 库暴露了一个属性 response.next,可用于获取下一个重定向请求。

session = requests.Session()
request = requests.Request("GET", ...).prepare()
while request is not None:
    response = session.send(request, allow_redirects=False)
    request = response.next

在 HTTPX 中,该属性命名为 response.next_request。例如:

client = httpx.Client()
request = client.build_request("GET", ...)
while request is not None:
    response = client.send(request)
    request = response.next_request

请求内容

对于上传原始文本或二进制内容,我们更倾向于使用 content 参数,以便更好地区分这种情况与上传表单数据的情况。

例如,使用 content=... 上传原始内容:

# 上传文本、字节或字节迭代器

使用 `content=...` 上传原始请求体

```python
# 上传原始字节
httpx.post(..., content=b"Hello, world")

使用 data=... 发送表单数据:

# 上传表单数据
httpx.post(..., data={"message": "Hello, world"})

使用 data=<文本/字节内容> 会触发弃用警告,并将在 HTTPX 1.0 版本中完全移除。

上传文件

HTTPX 严格要求上传文件必须以二进制模式打开,以避免因尝试上传文本模式打开的文件而导致的字符编码问题。

内容编码

HTTPX 使用 utf-8 编码 str 类型的请求体。例如,当使用 content=<字符串> 时,请求体将在发送前被编码为 utf-8。这与使用 latin1 编码的 Requests 库不同。如果需要显式指定编码,请直接传递编码后的字节,例如 content=<字符串>.encode("latin1")

对于响应体,如果服务器没有发送明确的编码,HTTPX 会尽力确定合适的编码。HTTPX 使用 charset_normalizer 来猜测解码响应时应使用的编码。如果无法确定或内容少于 32 个字节,将使用 utf-8 编码并采用 error="replace" 解码策略。

Cookies

如果使用客户端实例,则 cookie 应始终设置在客户端上,而不是基于每个请求单独设置。

以下用法是支持的:

client = httpx.Client(cookies=...)
client.post(...)

以下用法支持:

client = httpx.Client()
client.post(..., cookies=...)

我们倾向于在此强制执行更严格的 API,因为它能提供更清晰的 cookie 持久性预期,特别是在发生重定向时。

状态码

在我们的文档中,我们更倾向于使用大写版本,如 codes.NOT_FOUND,但为了保持与 requests 的 API 兼容性,也提供了小写版本。

Requests 包含了许多 HTTPX 不支持的状态码同义词。

流式响应

HTTPX 提供了 .stream() 接口,而不是使用 stream=True。这确保了流式响应在流块外部总能被正确关闭,并且更直观地标明了可以在哪些点对响应使用流式 I/O API。

例如:

with httpx.stream("GET", "https://www.example.com") as response:
    ...

stream() 块内,请求数据可以通过以下方式获取:

  • .iter_bytes() - 替代 response.iter_content()
  • .iter_text() - 替代 response.iter_content(decode_unicode=True)
  • .iter_lines() - 对应 response.iter_lines()
  • .iter_raw() - 使用此方法替代 response.raw
  • .read() - 读取整个响应体,使 response.textresponse.content 可用。

超时设置

HTTPX 默认对所有网络操作包含合理的超时设置,而 Requests 默认没有超时限制。

要获得与 Requests 相同的行为,请将 timeout 参数设为 None

httpx.get('https://www.example.com', timeout=None)

代理键配置

HTTPX 使用 mounts 参数来实现 HTTP 代理和传输路由功能。它不仅支持代理配置,还能实现更复杂的路由规则。详细文档请参阅 传输挂载

当使用 httpx.Client(mounts={...}) 来映射不同的传输方式时,我们需要使用完整的 URL 协议方案,例如 mounts={"http://": ..., "https://": ...}

这与 requests 库的 proxies={"http": ..., "https": ...} 用法不同。

这一变更是为了更好支持复杂路由映射场景,例如包含域名的情况:mounts={"all://": ..., httpx.HTTPTransport(proxy="all://www.example.com": None}) 表示将所有请求路由到代理,但显式排除了对 "www.example.com" 的请求。

另外需要注意的是,requests.Session.request(...) 允许传入 proxies=... 参数,而 httpx.Client.request(...) 不允许传入 mounts=... 参数。

SSL 配置

使用 Client 实例时,SSL 配置应该总是在客户端初始化时传入,而不是在请求方法中传入。

如果需要多种不同的 SSL 配置,应该为每种配置创建不同的客户端实例。

HTTP 方法的请求体

HTTP 规范中 GETDELETEHEADOPTIONS 方法被定义为不支持请求体。为了遵循这一规范,.get.delete.head.options 方法不支持 contentfilesdatajson 参数。

如果确实需要使用这些 HTTP 方法发送请求数据,应该改用通用的 .request 方法。

httpx.request(
  method="DELETE",
  url="https://www.example.com/",
  content=b'DELETE 请求中的请求体数据。'
)

检查成功与失败响应

我们不支持 response.is_ok,因为该命名存在歧义,可能会错误地暗示与 response.status_code == codes.OK 等价。相反,我们提供了 response.is_success 属性,可用于检查 2xx 响应。

请求实例化

HTTPX 中没有 prepared requests 的概念。如果需要自定义请求实例化,请参阅 请求实例

此外,httpx.Request() 不支持 authtimeoutfollow_redirectsmountsverifycert 参数。但这些参数在 httpx.requesthttpx.gethttpx.post 等方法中可用,也可以在 Client 实例 上使用。

模拟测试

如果需要像 responsesrequests-mockrequests 提供测试工具那样模拟 HTTPX,请参阅 RESPX

缓存

如果使用 cachecontrolrequests-cacherequests 库添加 HTTP 缓存支持,可以为 HTTPX 使用 Hishel

网络层

requests 将其大部分 HTTP 网络代码委托给优秀的 urllib3 处理。

而 HTTPX 使用 HTTPCore 作为其核心 HTTP 网络层,这是一个不同于 urllib3 的项目。

查询参数

requests 会自动忽略值为 Noneparams 参数(例如 requests.get(..., params={"foo": None}))。HTTPX 不支持这种处理方式。

对于查询参数 (params=) 和表单数据 (data=),requests 支持发送元组列表(例如 requests.get(..., params=[('key1', 'value1'), ('key1', 'value2')]))。HTTPX 不支持这种格式,而是应该使用值为列表的字典。例如:httpx.get(..., params={'key1': ['value1', 'value2']}) 或表单数据形式:httpx.post(..., data={'key1': ['value1', 'value2']})

事件钩子

requests 允许事件钩子修改 RequestResponse 对象。具体示例可参阅 requests 文档中的示例

在 HTTPX 中,事件钩子可以访问请求和响应的属性,但钩子回调函数不能修改原始的请求/响应对象。

如果需要更精细的控制,可以考虑使用自定义传输层