Go が localhost への通信でプロキシを迂回する理由
Go に組み込まれたループバック除外と NO_PROXY 設定の違いを理解し、環境変数による経路選択と明示的な ProxyURL を比較します。
Go の環境変数ベースのプロキシ選択器には、localhost とループバック IP の宛先を除外する規則が組み込まれています。NO_PROXY を空にしてもこの例外はなくなりません。そのため、公開ホスト名へのリクエストは想定どおりプロキシを使う一方で、ローカルテストは直接接続になることがあります。
この規則が対象とするのはリクエストの宛先です。プロキシの待ち受けアドレス自体が 127.0.0.1 であることは妨げません。
リクエストを送らずに選択器を確認する
package main
import (
"fmt"
"net/http"
"net/url"
)
func main() {
fixed, _ := url.Parse("http://203.0.113.10:8080")
for _, target := range []string{
"http://localhost:8000/",
"http://127.0.0.1:8000/",
"http://example.com/",
} {
request, _ := http.NewRequest("GET", target, nil)
discovered, err := http.ProxyFromEnvironment(request)
explicit, _ := http.ProxyURL(fixed)(request)
fmt.Println(target, discovered, explicit, err)
}
}
環境設定による比較結果を確認したい場合は、そのプロセスにプロキシ変数を設定してから実行します。このプログラムは選択器を評価するだけで、文書例のプロキシにも、いずれの宛先にも接続しません。
環境からの検出と明示的な選択器は異なる方針
ProxyFromEnvironment は、宛先のスキーム、環境設定、ループバックの特別扱いを含む迂回規則を考慮します。ProxyURL は、その選択器に渡されたすべてのリクエストに対して、指定されたプロキシ URL を返します。
したがって、明示的な ProxyURL を持つ専用のトランスポート なら、ローカルの宛先への通信もプロキシ経由にできます。ただし、それが役立つのは、プロキシが要求された宛先へ正当に到達できる場合だけです。リモートプロキシにとっての localhost は手元のノート PC の localhost ではないため、経路を強制しても有用な接続テストになるとは限りません。
プロセスが環境をキャッシュする前に確認する
標準 net/http の環境プロキシ設定は、最初の使用後にキャッシュされます。同じプログラムの実行中に後から環境変数を変えても、新しい設定でのテストを確実に繰り返す方法にはなりません。意図した値を設定して新しいプロセスを起動するか、動作を自分で制御できる明示的な選択器を指定してください。
このループバックの動作は Go 1.27.3 の標準プロキシ選択器に適用されます。他の言語や HTTP クライアントは、localhost に異なる経路選択規則を使うことがあります。