Requests PreparedRequest 与缺失的环境设置
让自定义预备请求保持 Requests 常规的代理与 CA 证书包处理行为,而不笼统假定所有底层 send 都忽略代理。
请求可能通过 session.get() 正常工作,却在改写为 PreparedRequest 后证书验证失败。底层 send 路径不会执行与普通 request 方法相同的环境合并。
import requests
with requests.Session() as session:
request = requests.Request("GET", "https://example.com/")
prepared = session.prepare_request(request)
settings = session.merge_environment_settings(
prepared.url, {}, None, None, None
)
response = session.send(
prepared,
timeout=(5, 15),
**settings,
)
response.raise_for_status()
print(response.status_code)
在完成预期的 URL 修改后,使用最终准备好的 URL 合并设置。代理和绕过决策取决于目标,因此为早先 URL 获取的设置,可能不适合实际发送的请求。
CA 设置很容易遗漏
启用常规环境信任时,如果没有显式覆盖验证设置,合并会考虑 REQUESTS_CA_BUNDLE 及其回退 CURL_CA_BUNDLE。直接以默认 verify 设置调用 send,不会执行该 CA 查找。关闭验证只是掩盖差异,并没有提供预期的证书存储。
Session.prepare_request() 还会应用会话的准备行为。直接使用 Request.prepare() 创建请求是另一种选择,不应期待它自动应用会话 Cookie 或其他会话准备。
代理有更具体的规则
说所有 PreparedRequest 都忽略代理环境变量并不准确。在 Requests 2.34.2 中,如果没有提供 proxies 关键字参数,send 会解析默认代理。向 send 提供 proxies={},会跳过这一特定的默认解析分支。
传给 merge_environment_settings 的空字典作用不同:合并可以先将适用的环境路由填入其中,再传给 send。只看到两个代码片段中都出现空字典,就会忽略接收它们的方法并不相同。
对于自定义请求构建代码,将准备、环境合并和发送放在一起。应用有意使用 trust_env=False 时,合并会遵守这一策略;它不能把环境设置强行注入主动关闭环境信任的客户端。