[インデックス 15708] ファイルの概要
このコミットは、Go言語の標準ライブラリである net/http パッケージにおける http.Client と http.Transport の役割と関係性に関するドキュメントを改善するものです。特に、これらの型がどのようにHTTPリクエストを処理し、接続を管理するかについて、より詳細な説明を追加しています。
コミット
commit 864278ad90383182456feb79df3cd62fe4f9cf4d
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Mon Mar 11 18:51:01 2013 -0700
net/http: bit more docs on Client vs Transport
This isn't as bad as it used to be, but add a bit
more detail to close the issue.
Fixes #3359
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/7606044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/864278ad90383182456feb79df3cd62fe4f9cf4d
元コミット内容
このコミットは、net/http パッケージの Client と Transport に関するドキュメントを修正・追加しています。
具体的には以下の変更が含まれます。
src/pkg/net/http/client.go:Client型のコメントに、ClientがRoundTripper(例:Transport) よりも高レベルであり、クッキーやリダイレクトなどのHTTPの詳細を処理することが追記されました。src/pkg/net/http/response.go:Response.Bodyのコメントに、サーバーが "chunked"Transfer-Encodingで応答した場合、Bodyが自動的にデチャンクされることが追記されました。src/pkg/net/http/transport.go:Transport型のコメントから、TODOコメント(グローバルな最大キャッシュ接続数、キャッシュ接続のタイムアウト、パイプライン処理に関するもの)が削除され、DisableKeepAlivesとDisableCompressionの説明がより詳細になりました。RoundTripメソッドのコメントに、高レベルのHTTPクライアントサポート(クッキーやリダイレクトの処理など)についてはGet、Post、およびClient型を参照するよう追記されました。
変更の背景
このコミットは、Goの net/http パッケージにおける Client と Transport の役割に関する混乱を解消し、ドキュメントを改善することを目的としています。コミットメッセージにある Fixes #3359 は、GitHubのIssue #3359を修正したことを示しています。このIssueは、http.Client と http.Transport の違いや適切な使用方法について、より明確なドキュメントが必要であるというユーザーからのフィードバックに基づいていると考えられます。
以前は、Client と Transport の関係性が十分に説明されておらず、開発者がどちらを使用すべきか、またそれぞれの内部動作について理解しにくい状況がありました。特に、Transport がTCP接続のキャッシュなどの低レベルな詳細を扱い、Client がクッキーやリダイレクトといった高レベルなHTTPプロトコルの詳細を扱うという役割分担が不明瞭でした。このコミットは、これらの点を明確にすることで、開発者が net/http パッケージをより効果的に利用できるようにすることを意図しています。
前提知識の解説
Go言語の net/http パッケージは、HTTPクライアントとサーバーを構築するための強力な機能を提供します。このコミットを理解するためには、以下の主要な概念を把握しておく必要があります。
-
http.Client:http.Clientは、HTTPリクエストを送信するための高レベルなインターフェースを提供します。- 通常、アプリケーションでHTTPリクエストを行う際に直接使用するエントリポイントです。
Clientは、リダイレクトの自動処理、クッキーの管理、認証、リクエストのタイムアウト設定など、HTTPプロトコルレベルの多くの詳細を抽象化します。Clientのゼロ値 (http.DefaultClient) はすぐに使用可能で、デフォルトのTransportを使用します。Clientは内部にTransportを持ち、実際のネットワーク通信はそのTransportに委譲されます。Clientはゴルーチンセーフであり、複数のゴルーチンから同時に使用できます。また、内部にTCP接続のキャッシュを持つため、リクエストごとに新しいClientを作成するのではなく、再利用することが推奨されます。
-
http.Transport:http.Transportは、HTTPリクエストの実際のネットワーク通信を担当する低レベルなコンポーネントです。Transportはhttp.RoundTripperインターフェースを実装しており、単一のHTTPトランザクション(リクエストの送信とレスポンスの受信)を実行します。- 主な役割は、TCP接続の確立、TLSハンドシェイク、HTTP/1.xまたはHTTP/2プロトコルの実装、接続の再利用(Keep-Alive)、プロキシの処理、圧縮の処理などです。
Transportは、TCP接続のプールを管理し、同じホストへの複数のリクエストで接続を再利用することでパフォーマンスを向上させます。- 通常、
ClientのTransportフィールドを通じて設定されます。カスタムのTransportを使用することで、TLS設定、プロキシ設定、接続のタイムアウト、Keep-Aliveの挙動などを細かく制御できます。
-
http.RoundTripperインターフェース:type RoundTripper interface { RoundTrip(*Request) (*Response, error) }- このインターフェースは、単一のHTTPリクエストを送信し、そのレスポンスを受け取るためのメソッド
RoundTripを定義します。 http.Transportはこのインターフェースの実装の一つです。- ミドルウェアやカスタムのHTTPクライアントロジックを実装する際に、このインターフェースをラップしたり、独自に実装したりすることがあります。
-
HTTP Keep-Alive (持続的接続):
- HTTP/1.1以降で導入された機能で、一つのTCP接続上で複数のHTTPリクエスト/レスポンスをやり取りすることを可能にします。
- これにより、リクエストごとに新しいTCP接続を確立するオーバーヘッド(TCPスリーウェイハンドシェイク、TLSハンドシェイクなど)を削減し、パフォーマンスを向上させます。
http.TransportはデフォルトでKeep-Aliveをサポートし、接続をプールして再利用します。
-
HTTP 圧縮 (Content-Encoding):
- HTTPでは、サーバーがレスポンスボディを圧縮して送信し、クライアントがそれを解凍することで、ネットワーク帯域幅の使用量を削減できます。
- クライアントは
Accept-Encodingヘッダーでサポートする圧縮方式(例:gzip,deflate,br)をサーバーに伝えます。 http.Transportは、デフォルトでAccept-Encoding: gzipをリクエストヘッダーに追加し、圧縮されたレスポンスを自動的に解凍します。
-
チャンク転送エンコーディング (Chunked Transfer-Encoding):
- HTTP/1.1で導入された転送エンコーディングの一種で、レスポンスボディのサイズが事前に不明な場合や、大きなレスポンスをストリーミングで送信する場合に使用されます。
- ボディは、サイズを示すヘッダーと実際のデータブロック(チャンク)の連続として送信され、最後にゼロサイズのチャンクで終了します。
- クライアントは、このチャンクを読み取りながらデコードする必要があります。
これらの概念を理解することで、コミットが Client と Transport のドキュメントをどのように改善し、それぞれの役割を明確にしているかがより深く理解できます。
技術的詳細
このコミットの技術的詳細は、主にGoの net/http パッケージ内のドキュメントコメントの追加と修正にあります。
-
http.Clientのドキュメント強化 (src/pkg/net/http/client.go):- 変更前:
// A Client is an HTTP client. Its zero value (DefaultClient) is a usable client // that uses DefaultTransport. // // The Client's Transport typically has internal state (cached // TCP connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. - 変更後:
// A Client is an HTTP client. Its zero value (DefaultClient) is a // usable client that uses DefaultTransport. // // The Client's Transport typically has internal state (cached TCP // connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. // // A Client is higher-level than a RoundTripper (such as Transport) // and additionally handles HTTP details such as cookies and // redirects. - 追加された行は、
ClientがRoundTripper(例:Transport) よりも「高レベル」であること、そして「クッキーやリダイレクトなどのHTTPの詳細を処理する」ことを明確にしています。これは、開発者がClientを使用する主な理由と、Transportとの役割分担を理解する上で非常に重要です。Clientはユーザーが直接操作するHTTPクライアントの「顔」であり、Transportはその背後で実際の通信を行う「エンジン」であるという関係性を強調しています。
- 変更前:
-
http.Response.Bodyのドキュメント追加 (src/pkg/net/http/response.go):- 変更前:
// The http Client and Transport guarantee that Body is always // non-nil, even on responses without a body or responses with // a zero-lengthed body. Body io.ReadCloser - 変更後:
// The http Client and Transport guarantee that Body is always // non-nil, even on responses without a body or responses with // a zero-lengthed body. // // The Body is automatically dechunked if the server replied // with a "chunked" Transfer-Encoding. Body io.ReadCloser - 追加された行は、
Response.Bodyがchunked Transfer-Encodingで送られてきた場合に自動的にデチャンクされることを明記しています。これは、Goのnet/httpパッケージがチャンク転送のデコードを透過的に処理するため、アプリケーション開発者がその詳細を意識する必要がないことを示しています。これにより、開発者はBodyを通常のio.Readerとして扱うことができ、利便性が向上します。
- 変更前:
-
http.Transportのドキュメント改善とTODOコメントの削除 (src/pkg/net/http/transport.go):-
TODOコメントの削除:
--- a/src/pkg/net/http/transport.go +++ b/src/pkg/net/http/transport.go @@ -49,10 +49,6 @@ type Transport struct { altMu sync.RWMutex altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper - // TODO: tunable on global max cached connections - // TODO: tunable on timeout on cached connections - // TODO: optional pipelining - // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the // request is aborted with the provided error.これらの
TODOコメントは、将来的な機能拡張のアイデアを示していましたが、このコミットでは削除されました。これは、これらの機能がまだ実装されていないか、または実装の優先度が低いと判断されたためと考えられます。代わりに、既存の機能に関するドキュメントの明確化に焦点が当てられています。 -
DisableKeepAlivesとDisableCompressionの説明強化:--- a/src/pkg/net/http/transport.go +++ b/src/pkg/net/http/transport.go @@ -68,7 +64,18 @@ type Transport struct { // tls.Client. If nil, the default configuration is used. TLSClientConfig *tls.Config - DisableKeepAlives bool + // DisableKeepAlives, if true, prevents re-use of TCP connections + // between different HTTP requests. + DisableKeepAlives bool + + // DisableCompression, if true, prevents the Transport from + // requesting compression with an "Accept-Encoding: gzip" + // request header when the Request contains no existing + // Accept-Encoding value. If the Transport requests gzip on + // its own and gets a gzipped response, it's transparently + // decoded in the Response.Body. However, if the user + // explicitly requested gzip it is not automatically + // uncompressed. DisableCompression bool // MaxIdleConnsPerHost, if non-zero, controls the maximum idleDisableKeepAlivesとDisableCompressionのコメントが大幅に拡張され、それぞれのフィールドが具体的にどのような挙動を制御するのかが詳細に説明されています。DisableKeepAlives: TCP接続の再利用を防ぐことを明確にしています。DisableCompression:Accept-Encoding: gzipヘッダーの自動追加を防ぐこと、およびTransportが独自に圧縮をリクエストした場合とユーザーが明示的にリクエストした場合のレスポンスボディのデコード挙動の違いを詳細に説明しています。特に、ユーザーが明示的にgzipをリクエストした場合は自動的に解凍されないという点は、開発者が圧縮されたレスポンスを扱う際に注意すべき重要な点です。
-
Transport.RoundTripメソッドのドキュメント追加:--- a/src/pkg/net/http/transport.go +++ b/src/pkg/net/http/transport.go @@ -133,6 +143,9 @@ func (tr *transportRequest) extraHeaders() Header { }\n \n // RoundTrip implements the RoundTripper interface.\n+//\n+// For higher-level HTTP client support (such as handling of cookies\n+// and redirects), see Get, Post, and the Client type.\n func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) { \tif req.URL == nil { \t\treturn nil, errors.New(\"http: nil Request.URL\")RoundTripメソッドのコメントに、高レベルのHTTPクライアントサポート(クッキーやリダイレクトの処理など)が必要な場合は、Get、Post、およびClient型を参照するよう促す文言が追加されました。これは、Transport.RoundTripが低レベルな操作であり、ほとんどのアプリケーションではhttp.Clientを通じてHTTPリクエストを行うべきであるというベストプラクティスを強調しています。
-
これらの変更は、Goの net/http パッケージのドキュメントの品質を向上させ、開発者が Client と Transport の違いと適切な使用方法をより明確に理解できるようにすることを目的としています。特に、それぞれの型の責任範囲を明確にすることで、APIの誤用を防ぎ、より堅牢なHTTPクライアントアプリケーションの構築を支援します。
コアとなるコードの変更箇所
このコミットは、主にGoの標準ライブラリ src/pkg/net/http ディレクトリ内の以下の3つのファイルにドキュメントコメントの変更を加えています。
-
src/pkg/net/http/client.go:Client型の定義コメントに、ClientがRoundTripperよりも高レベルであり、クッキーやリダイレクトを処理する旨の記述が追加されました。
-
src/pkg/net/http/response.go:Response型のBodyフィールドのコメントに、チャンク転送エンコーディングが自動的にデチャンクされる旨の記述が追加されました。
-
src/pkg/net/http/transport.go:Transport型の定義コメントから、いくつかのTODOコメントが削除されました。DisableKeepAlivesとDisableCompressionフィールドのコメントが拡張され、それぞれの挙動がより詳細に説明されました。RoundTripメソッドのコメントに、高レベルのHTTPクライアントサポートについてはClient型を参照するよう促す記述が追加されました。
これらの変更は、コードの振る舞いを直接変更するものではなく、APIの利用者がその意図と挙動をより正確に理解できるようにするためのドキュメント改善が主眼です。
コアとなるコードの解説
このコミットは、Goの net/http パッケージのドキュメントを改善することで、http.Client と http.Transport の役割分担を明確にし、開発者がこれらのコンポーネントを適切に利用できるようにすることを目的としています。
src/pkg/net/http/client.go の変更
--- a/src/pkg/net/http/client.go
+++ b/src/pkg/net/http/client.go
@@ -19,12 +19,16 @@ import (
"strings"
)
-// A Client is an HTTP client. Its zero value (DefaultClient) is a usable client
-// that uses DefaultTransport.
+// A Client is an HTTP client. Its zero value (DefaultClient) is a
+// usable client that uses DefaultTransport.
//
-// The Client's Transport typically has internal state (cached
-// TCP connections), so Clients should be reused instead of created as
+// The Client's Transport typically has internal state (cached TCP
+// connections), so Clients should be reused instead of created as
// needed. Clients are safe for concurrent use by multiple goroutines.
+//
+// A Client is higher-level than a RoundTripper (such as Transport)
+// and additionally handles HTTP details such as cookies and
+// redirects.
type Client struct {
// Transport specifies the mechanism by which individual
// HTTP requests are made.
この変更は、http.Client のコメントに以下の重要な情報を追加しています。
ClientはRoundTripper(例:Transport) よりも「高レベル」であること。Clientは「クッキーやリダイレクトなどのHTTPの詳細を処理する」こと。
これにより、Client が単なるリクエスト送信器ではなく、HTTPプロトコルレベルの複雑な挙動(リダイレクト追跡、クッキーの送受信など)を自動的に処理する高機能なクライアントであることが明確になります。開発者は通常、これらの高レベルな機能が必要なため、直接 Client を使用することが推奨されます。
src/pkg/net/http/response.go の変更
--- a/src/pkg/net/http/response.go
+++ b/src/pkg/net/http/response.go
@@ -46,6 +46,9 @@ type Response struct {
// The http Client and Transport guarantee that Body is always
// non-nil, even on responses without a body or responses with
// a zero-lengthed body.
+ //
+ // The Body is automatically dechunked if the server replied
+ // with a "chunked" Transfer-Encoding.
Body io.ReadCloser
// ContentLength records the length of the associated content. The
この変更は、http.Response の Body フィールドのコメントに、サーバーが chunked Transfer-Encoding で応答した場合に Body が自動的にデチャンクされることを追記しています。これは、Goの net/http パッケージがチャンク転送のデコードを透過的に処理するため、開発者が io.ReadCloser として Body を読み込む際に、チャンクの境界を意識する必要がないことを示しています。これにより、APIの使いやすさが向上します。
src/pkg/net/http/transport.go の変更
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -49,10 +49,6 @@ type Transport struct {
altMu sync.RWMutex
altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
- // TODO: tunable on global max cached connections
- // TODO: tunable on timeout on cached connections
- // TODO: optional pipelining
-
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
// request is aborted with the provided error.
@@ -68,7 +64,18 @@ type Transport struct {
// tls.Client. If nil, the default configuration is used.
TLSClientConfig *tls.Config
- DisableKeepAlives bool
+ // DisableKeepAlives, if true, prevents re-use of TCP connections
+ // between different HTTP requests.
+ DisableKeepAlives bool
+
+ // DisableCompression, if true, prevents the Transport from
+ // requesting compression with an "Accept-Encoding: gzip"
+ // request header when the Request contains no existing
+ // Accept-Encoding value. If the Transport requests gzip on
+ // its own and gets a gzipped response, it's transparently
+ // decoded in the Response.Body. However, if the user
+ // explicitly requested gzip it is not automatically
+ // uncompressed.
DisableCompression bool
// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
@@ -81,6 +88,9 @@ type Transport struct {
// writing the request (including its body, if any). This
// time does not include the time to read the response body.
ResponseHeaderTimeout time.Duration
+
+ // TODO: tunable on global max cached connections
+ // TODO: tunable on timeout on cached connections
}
// ProxyFromEnvironment returns the URL of the proxy to use for a
@@ -133,6 +143,9 @@ func (tr *transportRequest) extraHeaders() Header {
}
// RoundTrip implements the RoundTripper interface.
+//
+// For higher-level HTTP client support (such as handling of cookies
+// and redirects), see Get, Post, and the Client type.
func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
if req.URL == nil {
return nil, errors.New("http: nil Request.URL")
transport.go の変更は多岐にわたります。
- TODOコメントの削除: 以前の
TODOコメントは、将来的な機能拡張のアイデアでしたが、このコミットでは削除されました。これは、ドキュメントの明確化に焦点を当て、未実装の機能に関する混乱を避けるためと考えられます。 DisableKeepAlivesの説明強化:DisableKeepAlivesがtrueの場合にTCP接続の再利用が防止されることが明確に記述されました。これは、Keep-Alive接続の挙動を制御したい開発者にとって重要な情報です。DisableCompressionの説明強化:DisableCompressionがtrueの場合にAccept-Encoding: gzipヘッダーが自動的に追加されないこと、そしてTransportが独自に圧縮をリクエストした場合とユーザーが明示的にリクエストした場合のレスポンスボディのデコード挙動の違いが詳細に説明されました。特に、ユーザーが明示的にgzipをリクエストした場合は自動的に解凍されないという点は、開発者が圧縮されたレスポンスを扱う際に注意すべき重要な点です。RoundTripメソッドのコメント追加:RoundTripメソッドのコメントに、高レベルのHTTPクライアントサポート(クッキーやリダイレクトの処理など)が必要な場合は、Get、Post、およびClient型を参照するよう促す文言が追加されました。これは、Transport.RoundTripが低レベルな操作であり、ほとんどのアプリケーションではhttp.Clientを通じてHTTPリクエストを行うべきであるというベストプラクティスを強調しています。
これらの変更は、http.Transport が低レベルなネットワーク通信と接続管理を担当するコンポーネントであることを再確認させ、その設定オプションの挙動をより詳細に説明することで、開発者が Transport をカスタマイズする際の理解を深めることを目的としています。
全体として、このコミットはGoの net/http パッケージのドキュメントを改善し、http.Client と http.Transport の役割と責任範囲を明確にすることで、APIの使いやすさと理解度を向上させています。
関連リンク
- Go言語
net/httpパッケージのドキュメント: https://pkg.go.dev/net/http - Go言語のIssue #3359:
net/http: Client vs Transport docs(このコミットによって修正されたIssue) - GitHubのIssueトラッカーで検索することで詳細を確認できます。
参考にした情報源リンク
- Go言語の公式ドキュメント (
pkg.go.dev) - GitHubのgolang/goリポジトリのコミット履歴
- Go言語のHTTPクライアントに関する一般的な解説記事 (例: "Go HTTP Client Best Practices", "Understanding Go's net/http Package") - これらの記事は、
ClientとTransportの概念をより深く理解するために参照しました。- 例: https://medium.com/@nate510/don-t-defer-close-on-http-client-responses-19d2c9d50890 (これは一般的なベストプラクティスに関する記事ですが、
ClientとTransportの文脈で役立ちます) - 例: https://www.alexedwards.net/blog/making-http-requests-in-go (GoでのHTTPリクエストに関する基本的な解説)
- 例: https://eli.thegreenplace.net/2020/go-http-client-and-connection-pooling/ (GoのHTTPクライアントと接続プーリングに関する詳細な解説)
- これらの記事は、
ClientとTransportの関係性、接続の再利用、および一般的なHTTPクライアントのベストプラクティスについて理解を深めるのに役立ちました。
- 例: https://medium.com/@nate510/don-t-defer-close-on-http-client-responses-19d2c9d50890 (これは一般的なベストプラクティスに関する記事ですが、