Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 15708] ファイルの概要

このコミットは、Go言語の標準ライブラリである net/http パッケージにおける http.Clienthttp.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 パッケージの ClientTransport に関するドキュメントを修正・追加しています。

具体的には以下の変更が含まれます。

  • src/pkg/net/http/client.go: Client 型のコメントに、ClientRoundTripper (例: Transport) よりも高レベルであり、クッキーやリダイレクトなどのHTTPの詳細を処理することが追記されました。
  • src/pkg/net/http/response.go: Response.Body のコメントに、サーバーが "chunked" Transfer-Encoding で応答した場合、Body が自動的にデチャンクされることが追記されました。
  • src/pkg/net/http/transport.go:
    • Transport 型のコメントから、TODO コメント(グローバルな最大キャッシュ接続数、キャッシュ接続のタイムアウト、パイプライン処理に関するもの)が削除され、DisableKeepAlivesDisableCompression の説明がより詳細になりました。
    • RoundTrip メソッドのコメントに、高レベルのHTTPクライアントサポート(クッキーやリダイレクトの処理など)については GetPost、および Client 型を参照するよう追記されました。

変更の背景

このコミットは、Goの net/http パッケージにおける ClientTransport の役割に関する混乱を解消し、ドキュメントを改善することを目的としています。コミットメッセージにある Fixes #3359 は、GitHubのIssue #3359を修正したことを示しています。このIssueは、http.Clienthttp.Transport の違いや適切な使用方法について、より明確なドキュメントが必要であるというユーザーからのフィードバックに基づいていると考えられます。

以前は、ClientTransport の関係性が十分に説明されておらず、開発者がどちらを使用すべきか、またそれぞれの内部動作について理解しにくい状況がありました。特に、Transport がTCP接続のキャッシュなどの低レベルな詳細を扱い、Client がクッキーやリダイレクトといった高レベルなHTTPプロトコルの詳細を扱うという役割分担が不明瞭でした。このコミットは、これらの点を明確にすることで、開発者が net/http パッケージをより効果的に利用できるようにすることを意図しています。

前提知識の解説

Go言語の net/http パッケージは、HTTPクライアントとサーバーを構築するための強力な機能を提供します。このコミットを理解するためには、以下の主要な概念を把握しておく必要があります。

  1. http.Client:

    • http.Client は、HTTPリクエストを送信するための高レベルなインターフェースを提供します。
    • 通常、アプリケーションでHTTPリクエストを行う際に直接使用するエントリポイントです。
    • Client は、リダイレクトの自動処理、クッキーの管理、認証、リクエストのタイムアウト設定など、HTTPプロトコルレベルの多くの詳細を抽象化します。
    • Client のゼロ値 (http.DefaultClient) はすぐに使用可能で、デフォルトの Transport を使用します。
    • Client は内部に Transport を持ち、実際のネットワーク通信はその Transport に委譲されます。
    • Client はゴルーチンセーフであり、複数のゴルーチンから同時に使用できます。また、内部にTCP接続のキャッシュを持つため、リクエストごとに新しい Client を作成するのではなく、再利用することが推奨されます。
  2. http.Transport:

    • http.Transport は、HTTPリクエストの実際のネットワーク通信を担当する低レベルなコンポーネントです。
    • Transporthttp.RoundTripper インターフェースを実装しており、単一のHTTPトランザクション(リクエストの送信とレスポンスの受信)を実行します。
    • 主な役割は、TCP接続の確立、TLSハンドシェイク、HTTP/1.xまたはHTTP/2プロトコルの実装、接続の再利用(Keep-Alive)、プロキシの処理、圧縮の処理などです。
    • Transport は、TCP接続のプールを管理し、同じホストへの複数のリクエストで接続を再利用することでパフォーマンスを向上させます。
    • 通常、ClientTransport フィールドを通じて設定されます。カスタムの Transport を使用することで、TLS設定、プロキシ設定、接続のタイムアウト、Keep-Aliveの挙動などを細かく制御できます。
  3. http.RoundTripper インターフェース:

    • type RoundTripper interface { RoundTrip(*Request) (*Response, error) }
    • このインターフェースは、単一のHTTPリクエストを送信し、そのレスポンスを受け取るためのメソッド RoundTrip を定義します。
    • http.Transport はこのインターフェースの実装の一つです。
    • ミドルウェアやカスタムのHTTPクライアントロジックを実装する際に、このインターフェースをラップしたり、独自に実装したりすることがあります。
  4. HTTP Keep-Alive (持続的接続):

    • HTTP/1.1以降で導入された機能で、一つのTCP接続上で複数のHTTPリクエスト/レスポンスをやり取りすることを可能にします。
    • これにより、リクエストごとに新しいTCP接続を確立するオーバーヘッド(TCPスリーウェイハンドシェイク、TLSハンドシェイクなど)を削減し、パフォーマンスを向上させます。
    • http.Transport はデフォルトでKeep-Aliveをサポートし、接続をプールして再利用します。
  5. HTTP 圧縮 (Content-Encoding):

    • HTTPでは、サーバーがレスポンスボディを圧縮して送信し、クライアントがそれを解凍することで、ネットワーク帯域幅の使用量を削減できます。
    • クライアントは Accept-Encoding ヘッダーでサポートする圧縮方式(例: gzip, deflate, br)をサーバーに伝えます。
    • http.Transport は、デフォルトで Accept-Encoding: gzip をリクエストヘッダーに追加し、圧縮されたレスポンスを自動的に解凍します。
  6. チャンク転送エンコーディング (Chunked Transfer-Encoding):

    • HTTP/1.1で導入された転送エンコーディングの一種で、レスポンスボディのサイズが事前に不明な場合や、大きなレスポンスをストリーミングで送信する場合に使用されます。
    • ボディは、サイズを示すヘッダーと実際のデータブロック(チャンク)の連続として送信され、最後にゼロサイズのチャンクで終了します。
    • クライアントは、このチャンクを読み取りながらデコードする必要があります。

これらの概念を理解することで、コミットが ClientTransport のドキュメントをどのように改善し、それぞれの役割を明確にしているかがより深く理解できます。

技術的詳細

このコミットの技術的詳細は、主にGoの net/http パッケージ内のドキュメントコメントの追加と修正にあります。

  1. 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.
      
    • 追加された行は、ClientRoundTripper (例: Transport) よりも「高レベル」であること、そして「クッキーやリダイレクトなどのHTTPの詳細を処理する」ことを明確にしています。これは、開発者が Client を使用する主な理由と、Transport との役割分担を理解する上で非常に重要です。Client はユーザーが直接操作するHTTPクライアントの「顔」であり、Transport はその背後で実際の通信を行う「エンジン」であるという関係性を強調しています。
  2. 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.Bodychunked Transfer-Encoding で送られてきた場合に自動的にデチャンクされることを明記しています。これは、Goの net/http パッケージがチャンク転送のデコードを透過的に処理するため、アプリケーション開発者がその詳細を意識する必要がないことを示しています。これにより、開発者は Body を通常の io.Reader として扱うことができ、利便性が向上します。
  3. 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 コメントは、将来的な機能拡張のアイデアを示していましたが、このコミットでは削除されました。これは、これらの機能がまだ実装されていないか、または実装の優先度が低いと判断されたためと考えられます。代わりに、既存の機能に関するドキュメントの明確化に焦点が当てられています。

    • DisableKeepAlivesDisableCompression の説明強化:

      --- 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
      

      DisableKeepAlivesDisableCompression のコメントが大幅に拡張され、それぞれのフィールドが具体的にどのような挙動を制御するのかが詳細に説明されています。

      • 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クライアントサポート(クッキーやリダイレクトの処理など)が必要な場合は、GetPost、および Client 型を参照するよう促す文言が追加されました。これは、Transport.RoundTrip が低レベルな操作であり、ほとんどのアプリケーションでは http.Client を通じてHTTPリクエストを行うべきであるというベストプラクティスを強調しています。

これらの変更は、Goの net/http パッケージのドキュメントの品質を向上させ、開発者が ClientTransport の違いと適切な使用方法をより明確に理解できるようにすることを目的としています。特に、それぞれの型の責任範囲を明確にすることで、APIの誤用を防ぎ、より堅牢なHTTPクライアントアプリケーションの構築を支援します。

コアとなるコードの変更箇所

このコミットは、主にGoの標準ライブラリ src/pkg/net/http ディレクトリ内の以下の3つのファイルにドキュメントコメントの変更を加えています。

  1. src/pkg/net/http/client.go:

    • Client 型の定義コメントに、ClientRoundTripper よりも高レベルであり、クッキーやリダイレクトを処理する旨の記述が追加されました。
  2. src/pkg/net/http/response.go:

    • Response 型の Body フィールドのコメントに、チャンク転送エンコーディングが自動的にデチャンクされる旨の記述が追加されました。
  3. src/pkg/net/http/transport.go:

    • Transport 型の定義コメントから、いくつかの TODO コメントが削除されました。
    • DisableKeepAlivesDisableCompression フィールドのコメントが拡張され、それぞれの挙動がより詳細に説明されました。
    • RoundTrip メソッドのコメントに、高レベルのHTTPクライアントサポートについては Client 型を参照するよう促す記述が追加されました。

これらの変更は、コードの振る舞いを直接変更するものではなく、APIの利用者がその意図と挙動をより正確に理解できるようにするためのドキュメント改善が主眼です。

コアとなるコードの解説

このコミットは、Goの net/http パッケージのドキュメントを改善することで、http.Clienthttp.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 のコメントに以下の重要な情報を追加しています。

  • ClientRoundTripper (例: 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.ResponseBody フィールドのコメントに、サーバーが 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 の説明強化: DisableKeepAlivestrue の場合にTCP接続の再利用が防止されることが明確に記述されました。これは、Keep-Alive接続の挙動を制御したい開発者にとって重要な情報です。
  • DisableCompression の説明強化: DisableCompressiontrue の場合に Accept-Encoding: gzip ヘッダーが自動的に追加されないこと、そして Transport が独自に圧縮をリクエストした場合とユーザーが明示的にリクエストした場合のレスポンスボディのデコード挙動の違いが詳細に説明されました。特に、ユーザーが明示的に gzip をリクエストした場合は自動的に解凍されないという点は、開発者が圧縮されたレスポンスを扱う際に注意すべき重要な点です。
  • RoundTrip メソッドのコメント追加: RoundTrip メソッドのコメントに、高レベルのHTTPクライアントサポート(クッキーやリダイレクトの処理など)が必要な場合は、GetPost、および Client 型を参照するよう促す文言が追加されました。これは、Transport.RoundTrip が低レベルな操作であり、ほとんどのアプリケーションでは http.Client を通じてHTTPリクエストを行うべきであるというベストプラクティスを強調しています。

これらの変更は、http.Transport が低レベルなネットワーク通信と接続管理を担当するコンポーネントであることを再確認させ、その設定オプションの挙動をより詳細に説明することで、開発者が Transport をカスタマイズする際の理解を深めることを目的としています。

全体として、このコミットはGoの net/http パッケージのドキュメントを改善し、http.Clienthttp.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") - これらの記事は、ClientTransport の概念をより深く理解するために参照しました。