🍡

PythonのrequestsでローカルAPIサーバにリクエストを送ろうとしたら沼った

に公開

状況

ローカルネットワークのAPIサーバに対してリクエストを送信しようとして、下記のような状況に陥りました。

サーバアクセスエラーが発生

  • Python(requests)

正常にレスポンスが返る

  • Javascript(Electron netモジュール)
  • PowerShell(Invoke-WebRequest)
  • Chrome

なぜ同じURLに対してリクエストを送っているにも関わらず、リクエストの方法によって結果が変わるのかわかりませんでした。

試したこと

  • User-AgentにMozilla/5.0などを指定
  • タイムアウトの指定
  • リクエスト先の変更

いずれも効果なし。

結論

Windowsの環境変数HTTP_PROXYHTTPS_PROXYが設定されていたことが原因でした。
Pythonのrequestsライブラリは、これらの環境変数が設定されていると、ローカル宛の通信であっても強制的にプロキシサーバを経由しようとします。その結果、プロキシ側で正しく処理できずエラーとなっていました。

一方で、JavaScript(Electron netモジュール)やPowerShellのInvoke-WebRequestは、Windowsのシステムプロキシ設定(インターネットオプションの設定)を参照するため、ローカル・イントラネット判定が効いて正常に通信できていたようです。

環境変数を_HTTP_PROXY_HTTPS_PROXYに変更してみるという対処もしていたのですが、VS Codeを再起動し忘れていて無駄に時間を溶かしました。
環境変数をいじったら再起動(戒め)。

解決策

環境変数を削除したり名前を変えたりする方法もありますが、NO_PROXY環境変数を設定するのがスマートです。 ここにプロキシを経由したくないホストを指定することで、HTTP_PROXYHTTPS_PROXYを維持したままローカル通信を通すことができます。

閑話

ちなみに、HTTP_PROXYHTTPS_PROXYを設定していた理由ですが、これはpipでライブラリをダウンロードする際にプロキシを経由しないと失敗することが背景にあったと思います(他にもこの環境変数を参照するソフトがあったはず)。思い返すと当時も沼っていましたね。

Discussion