[インデックス 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 idle
DisableKeepAlives
と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 (これは一般的なベストプラクティスに関する記事ですが、