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.text
和response.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 规范中 GET
、DELETE
、HEAD
和 OPTIONS
方法被定义为不支持请求体。为了遵循这一规范,.get
、.delete
、.head
和 .options
方法不支持 content
、files
、data
或 json
参数。
如果确实需要使用这些 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()
不支持 auth
、timeout
、follow_redirects
、mounts
、verify
和 cert
参数。但这些参数在 httpx.request
、httpx.get
、httpx.post
等方法中可用,也可以在 Client
实例 上使用。
模拟测试
如果需要像 responses
和 requests-mock
为 requests
提供测试工具那样模拟 HTTPX,请参阅 RESPX。
缓存
如果使用 cachecontrol
或 requests-cache
为 requests
库添加 HTTP 缓存支持,可以为 HTTPX 使用 Hishel。
网络层
requests
将其大部分 HTTP 网络代码委托给优秀的 urllib3
库 处理。
而 HTTPX 使用 HTTPCore 作为其核心 HTTP 网络层,这是一个不同于 urllib3
的项目。
查询参数
requests
会自动忽略值为 None
的 params
参数(例如 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
允许事件钩子修改 Request
和 Response
对象。具体示例可参阅 requests
文档中的示例。
在 HTTPX 中,事件钩子可以访问请求和响应的属性,但钩子回调函数不能修改原始的请求/响应对象。
如果需要更精细的控制,可以考虑使用自定义传输层。