PythonのrequestsでローカルAPIサーバにリクエストを送ろうとしたら沼った
状況
ローカルネットワークのAPIサーバに対してリクエストを送信しようとして、下記のような状況に陥りました。
サーバアクセスエラーが発生
- Python(requests)
正常にレスポンスが返る
- Javascript(Electron netモジュール)
- PowerShell(Invoke-WebRequest)
- Chrome
なぜ同じURLに対してリクエストを送っているにも関わらず、リクエストの方法によって結果が変わるのかわかりませんでした。
試したこと
- User-AgentにMozilla/5.0などを指定
- タイムアウトの指定
- リクエスト先の変更
いずれも効果なし。
結論
Windowsの環境変数HTTP_PROXYとHTTPS_PROXYが設定されていたことが原因でした。
Pythonのrequestsライブラリは、これらの環境変数が設定されていると、ローカル宛の通信であっても強制的にプロキシサーバを経由しようとします。その結果、プロキシ側で正しく処理できずエラーとなっていました。
一方で、JavaScript(Electron netモジュール)やPowerShellのInvoke-WebRequestは、Windowsのシステムプロキシ設定(インターネットオプションの設定)を参照するため、ローカル・イントラネット判定が効いて正常に通信できていたようです。
環境変数を_HTTP_PROXYと_HTTPS_PROXYに変更してみるという対処もしていたのですが、VS Codeを再起動し忘れていて無駄に時間を溶かしました。
環境変数をいじったら再起動(戒め)。
解決策
環境変数を削除したり名前を変えたりする方法もありますが、NO_PROXY環境変数を設定するのがスマートです。 ここにプロキシを経由したくないホストを指定することで、HTTP_PROXYとHTTPS_PROXYを維持したままローカル通信を通すことができます。
閑話
ちなみに、HTTP_PROXYとHTTPS_PROXYを設定していた理由ですが、これはpipでライブラリをダウンロードする際にプロキシを経由しないと失敗することが背景にあったと思います(他にもこの環境変数を参照するソフトがあったはず)。思い返すと当時も沼っていましたね。
Discussion