请求可能通过 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 时,合并会遵守这一策略;它不能把环境设置强行注入主动关闭环境信任的客户端。

相关文章