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を使う場合、マージはその方針を尊重します。環境設定を明示的に無効にしたクライアントへ強制する方法ではありません。

関連記事