SOCKS トンネルは TCP 接続を運びます。Go はそのトンネル越しに宛先と TLS を行い、そこで HTTP/2 をネゴシエートできます。SOCKS サーバー自身が HTTP/2 を話す必要はありません。

Go の標準デフォルトトランスポートを保持するプログラムでは、その設定を複製してプロキシを選びます。

import (
    "net/http"
    "net/url"
    "time"
)

proxyURL := &url.URL{
    Scheme: "socks5",
    Host: "proxy.example:1080",
}
transport := http.DefaultTransport.(*http.Transport).Clone()
transport.Proxy = http.ProxyURL(proxyURL)
client := &http.Client{
    Transport: transport,
    Timeout: 30 * time.Second,
}

プロキシと宛先は別々の値のままです。プロキシの値には SOCKS5 プロキシ一覧 から SOCKS5 エンドポイントを選びます。HTTP/2 はあくまで宛先とネゴシエートされます。client を使って実際の HTTPS サービス URL を要求し、その後はアプリケーションの通常のライフサイクルでレスポンスボディを閉じます。

標準デフォルトトランスポートは HTTP/2 をサポートしています。複製すればその設定を保ったままプロキシの選択を変えられます。型アサーションは、プログラムが http.DefaultTransport を別の RoundTripper に置き換えていないことを前提とします。

別途構築したトランスポートでは、特に独自の dial や TLS フックを渡す場合、その HTTP/2 設定を確認してください。Go は ForceAttemptHTTP2 を、新しいリリースではこれらの選択のための明示的な Protocols 設定を公開しています。

宛先は依然として TLS ネゴシエーションで HTTP/2 を提示する必要があります。成功したレスポンスの Proto または ProtoMajor の値を確認して、何が使われたかを見てください。SOCKS 経由で HTTPS 要求が成功したことは、ネゴシエートされたプロトコルが HTTP/2 だったことをそれ自体では証明しません。

関連記事