Golang の HTTP プロトコルに基づく Web サービス

HTTP プロトコルに基づく Web サービス

1. HTTPプロトコルのネットワークサービス

HTTP プロトコルは TCP/IP プロトコル スタックに基づいており、プレーン テキスト指向のプロトコルでもあります。

HTTP 要求メッセージ (メッセージのヘッダーと本文) に何を含める必要があるかがわかれば、任意のテキスト コンパイラを使用して完全な HTTP 要求メッセージを作成できます。

この場合、net.Dial関数を直接使用しても問題ありません。

net/httpコード パッケージ内のプログラム エンティティを使用すると、より便利に HTTP プロトコルに基づくネットワーク サービスにアクセスできます。これらの中で最も便利なのは、http.Get関数を使用することです。

1.1http.Get関数を使用して HTTP プロトコルの Web サービスにアクセスする

package main

import (
	"fmt"
	"net/http"
)

func main() {
    
    
	url1 := "http://www.google.cn/"
	fmt.Printf("Send request to %q with method GET ... \n", url1)
	response1, err := http.Get(url1)
	if err != nil {
    
    
		fmt.Printf("request sending error: %v\n", err)
	}
	defer response1.Body.Close()
	line1 := response1.Proto + " " + response1.Status
	fmt.Printf("The first line of response: \n %s \n", line1)
}

http.Getこの関数は、次の 2 つの結果値を返します。

  • 最初の結果値のタイプは、*http.ResponseWeb サービスによって返された応答コンテンツの構造化された表現です。
  • 2 番目の結果値はエラー タイプです。これは、HTTP 要求の作成と送信、および HTTP 応答の受信と解析のプロセス中に発生する可能性があるエラーを表します。

http.Getデフォルトの HTTP クライアントが関数内で使用され、その Get メソッドが呼び出されて関数が完成しますデフォルトのクライアント タイプは*http.Client、パブリック変数 DefaultClient で表される です。

1.2 デフォルト クライアント DefaultClient を使用する (タイプは*http.Client)

package main

import (
	"fmt"
	"net/http"
)

func main() {
    
    
	url1 := "http://www.google.cn/"
	fmt.Printf("Send request to %q with method GET ... \n", url1)
	// response1, err := http.Get(url1)
	response1, err := http.DefaultClient.Get(url1)
	if err != nil {
    
    
		fmt.Printf("request sending error: %v\n", err)
	}
	defer response1.Body.Close()
	line1 := response1.Proto + " " + response1.Status
	fmt.Printf("The first line of response: \n %s \n", line1)
}

そのプリミティブ型 ( http.Client) はそのまま使用できます。

1.3 http.ClientHTTP プロトコルにアクセスする Web サービスの使用

package main

import (
	"fmt"
	"net/http"
)

func main() {
    
    
	url1 := "http://www.google.cn/"
	fmt.Printf("Send request to %q with method GET ... \n", url1)
	// response1, err := http.Get(url1)
	// response1, err := http.DefaultClient.Get(url1)
	var oneClient http.Client
	response1, err := oneClient.Get(url1)
	if err != nil {
    
    
		fmt.Printf("request sending error: %v\n", err)
	}
	defer response1.Body.Close()
	line1 := response1.Proto + " " + response1.Status
	fmt.Printf("The first line of response: \n %s \n", line1)
}

http.Clientは構造体型で、含まれるフィールドは public です。このタイプのゼロ値を引き続き使用できる理由は、そのフィールドに応答のデフォルト値があるか、そのゼロ値を直接使用して特定の意味を表すことができるためです。

2.http.Clientのトランスポート フィールド

http.Client型の Transport フィールドは、Web サービスに HTTP リクエストを送信し、Web サービスから HTTP レスポンスを受信する操作プロセスを表します。

Transport フィールドの RoundTrip メソッドは、単一の HTTP トランザクション (または HTTP プロトコルに基づく単語の対話) に必要なすべてのステップを実装します。

Transport フィールドはhttp.RoundTripインターフェイス タイプであり、変数名が DefaultTransport であるデフォルト値があります。DefaultTransport の実際の型は再利用*http.Transportでき*http.Transport、スレッドセーフです。

http.ClientTransport フィールドへの明示的な割り当てがない場合、クライアントは DefaultTransport を直接使用します。

http.Clientの Timeout フィールドは、前述の HTTP トランザクションのタイムアウト期間を表します。これはtime.Durationタイプであり、タイムアウト期間が設定されていないことを示すために使用されるゼロ値が使用可能です。

(1)http.Transportタイプの DialContext フィールド

http.Transportタイプし、値のタイプを内部的に使用しnet.Dialer、値の Timeout フィールドの値を 30 秒に設定します。

つまり、Dialer の値が 30 秒以内にネットワーク接続を確立しなかった場合、操作タイムアウトと判断されます。

DefaultTransport の値が初期化されると、そのような Dialer 値の DialContext メソッドが以前の DialContext フィールドに割り当てられます。

var DefaultTransport RoundTripper = &Transport{
    
    
	Proxy: ProxyFromEnvironment,
	DialContext: defaultTransportDialContext(&net.Dialer{
    
    
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}),
	ForceAttemptHTTP2:     true,
	MaxIdleConns:          100,
	IdleConnTimeout:       90 * time.Second,
	TLSHandshakeTimeout:   10 * time.Second,
	ExpectContinueTimeout: 1 * time.Second,
}

func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
    
    
	return dialer.DialContext
}

KeepAlive の背後には、ネットワーク接続 (より正確には TCP 接続) の活性検出メカニズムがあります。その値は、プローブ パケットが送信される頻度を示すために使用されます。値が 0 以下の場合、このメカニズムが有効になっていないことを意味します。

DefaultTransport は、このフィールドの値を 30 秒に設定します。

(2)http.Transport型のその他のフィールド

タイムアウト操作について

  • IdleConnTimeout: 意味は、アイドル状態の接続が閉じられるまでの時間です。

    DefaultTransport は、このフィールドの値を 90 秒に設定します。

    値が 0 の場合、アイドル状態の接続が閉じられていないことを意味します。これにより、リソース リークが発生する可能性があることに注意してください。

  • ResponseHeaderTimeout: クライアントがオペレーティング システムに要求を完全に送信してから、オペレーティング システムから応答ヘッダーを受信するまでの最大時間を意味します。

    DefaultTransport は、このフィールドの値を設定しません。

  • ExpectContinueTimeout: クライアントがリクエスト ヘッダーを送信した後、最初のレスポンス ヘッダーを受信するまでに最も長い時間待機することを意味します。

    DefaultTransport は、このフィールドの値を 1 秒に設定します。

    クライアントが HTTP の「POST」メソッドを使用して大きなメッセージ本文をサーバーに送信する場合、まず「Expect: 100-continue」を含む要求ヘッダーを送信してサーバーに問い合わせることができます。メッセージ本文。このフィールドは、この場合のタイムアウト期間を設定するために使用されます。

    このフィールドの値が 0 以下の場合、リクエスト ボディがどれほど大きくても、すぐに送信されることに注意してください。

  • TLSHandshakeTimeout注: TLS は、Transport Layer Security の略で、Transport Layer Security と訳すことができます。このフィールドは、TLS プロトコルに基づく接続が確立されたときのハンドシェイク フェーズのタイムアウト時間を表します。

    DefaultTransport は、このフィールドの値を 10 秒に設定します。

    値が 0 の場合、この値に制限がないことを意味します。

に関連するいくつかのIdleConnTimeoutフィールド値

  • MaxIdleConns: すべてのホストにアクセスするための最大アイドル接続を制御するために使用されます。0 の場合、制限なし。

    DefaultTransport は MaxIdleConns を 100 に設定します。

    MaxIdleConns フィールドは、アイドル接続の総数のみを制限します。

  • MaxIdleConnsPerHost: Transport 値によってアクセスされる各ネットワーク サービスのアイドル接続の最大数を制御します。0 の場合、デフォルト値の 2 が使用され、 でDefaultMaxIdleConnsPerHost表されます。

    つまり、デフォルトでは、特定のトランスポート値によってアクセスされるネットワーク サービスごとに、アイドル状態の接続の数は最大 2 つです。

  • MaxConnsPerHost: 接続がアイドル状態かどうかに関係なく、特定のトランスポート値に対してアクセスされる各ネットワーク サービスの接続の最大数。

    このフィールドにはデフォルト値はありません。ゼロの値は制限がないことを意味します。

MaxIdleConnsアイドル接続の数に関連する2 つのMaxIdleConnsPerHostフィールドの値はリンクする必要があるため、実際の状況に応じてカスタマイズする必要がある場合があります。DefaultTransport 変数の宣言を参照できます。

3. アイドル接続があるのはなぜですか

3.1 アイドル接続の生成

HTTP プロトコルには、「Connection」と呼ばれるリクエスト ヘッダーがあります。HTTP プロトコルのバージョン 1.1 では、このヘッダーの値はデフォルトで「keep-alive」です。

この場合、ネットワーク接続は永続的な接続であり、現在の HTTP トランザクションが完了した後も接続を維持するため、再利用できます。

接続の再利用性により、次の 2 つの可能性がもたらされます。

  • 1 つの可能性は、同じ Web サービスに対して新しい HTTP 要求が送信され、接続が再利用されることです。
  • もう 1 つの可能性は、Web サービスへの HTTP 要求がなくなり、接続がアイドル状態になっていることです。(アイドル接続を生成)

後者の場合、アイドル接続が作成されます。また、特定のネットワーク サービスに割り当てられた接続が多すぎると、アイドル接続が生成されることもあります。新しく送信された HTTP 要求はそれぞれ、アイドル状態の接続のみを要求するためです。したがって、ほとんどの場合、アイドル接続の制限を設定する必要があり、考慮が必要です。

3.2 アイドル接続の生成をなくす

アイドル接続の生成を完全に排除したい場合は、初期化中に DisableKeepAlives フィールドの値を true に設定できます。このとき、HTTP リクエストの「Connection」ヘッダーの値は「close」に設定されます。これは、この Web 接続を維持する必要がないこと、および現在の HTTP トランザクションが完了した後に切断できることを Web サービスに伝えます。

このようにして、HTTP 要求が送信されるたびに、新しいネットワーク接続が生成されます。これを行うと、ネットワーク サービスとクライアントの負荷が大幅に増加します。したがって、通常の状況では、DisableKeepAlive フィールドを設定する必要はありません。

タイプにはnet.Dialer、似たように見えるフィールド KeepAlive もあります。ただし、前述の HTTP 永続接続の概念ではなく、KeepAlive は基になるソケットに直接作用します。

KeepAlive の背後には、ネットワーク接続 (より正確には TCP 接続) の活性検出メカニズムがあります。その値は、プローブ パケットが送信される頻度を示すために使用されます。値が 0 以下の場合、このメカニズムが有効になっていないことを意味します。DefaultTransport は、このフィールドの値を 30 秒に設定します。

四、http.Server

http.Serverタイプhttp.Clientは に対応します。http.ServerHTTP プロトコルに基づくサーバー、またはネットワーク サービスを表します。

4.1メソッドhttp.Serverの種類ListenAndServe

http.ServertypeListenAndServeメソッドの機能は、TCP プロトコルに基づいてネットワーク アドレスをリッスンし、受信した HTTP 要求を処理することです。

  • デフォルトでは、このメソッドはネットワーク接続の活性検出メカニズムを有効にして、接続が永続的であることを保証します。

  • 同時に、このメソッドは重大なエラーが発生するか、外部からオフにされるまで実行されます。

    外部からオフにされると、http.ErrServerClosed変数で表されるエラー値が返されます。

4.2ListenAndServeメソッドの主な機能

func (srv *Server) ListenAndServe() error {
    
    
	if srv.shuttingDown() {
    
    
		return ErrServerClosed
	}
	addr := srv.Addr
	if addr == "" {
    
    
		addr = ":http"
	}
	ln, err := net.Listen("tcp", addr)
	if err != nil {
    
    
		return err
	}
	return srv.Serve(ln)
}

ListenAndServeこのメソッドは、主に次のことを行います。

  1. Addr フィールドで現在のhttp.Serverタイプの値を確認してください。

    このフィールドの値は、現在のネットワーク サービスが使用する必要があるネットワーク アドレスを表します。つまり、IP アドレスとポート番号です。このフィールドの値が空の文字列の場合、代わりに ":http" が使用されます。

    つまり、このマシンを表すことができる任意のドメイン名と IP アドレスを使用し、ポート番号は 80 です。

  2. 関数を呼び出して、net.Listen決定したネットワークアドレスで TCP プロトコルに基づく監視を開始します。

  3. net.Listen関数が返すエラー値を確認してください。

    エラー値が nil でない場合は、値を直接返します。それ以外の場合は、現在の値の Serve メソッドを呼び出して、着信 HTTP 要求を受け入れて処理する準備をします。

4.3 (派生問題)net.Listen関数は何をするのか

net.Listen関数の機能:

  1. パラメータ値に含まれるネットワーク アドレスによって暗示された IP アドレスとポート番号を解析します。

  2. 与えられたネットワーク プロトコルに従って、監視方法を決定し、監視を開始します。

    これは、net.socket 関数とソケット関連の知識にも拡張できます。

4.4 (派生的な質問) http.ServerServe メソッドの型はどのように HTTP リクエストを受け入れて処理しますか?

for ループでは、ネットワーク監視の Accept メソッドが継続的に呼び出されます。

	for {
    
    
		rw, err := l.Accept()
  }

このメソッドは、次の 2 つの結果値を返します。

  • 最初の結果値はnet.Conn、新しい受信 HTTP 要求を含むネットワーク接続を表す型です。

  • 2 番目の結果値は、error考えられるエラーを表す型の値です。

    error が nil でない場合、一時的なエラーでない限り、ループは終了します。エラーが一時的なものである場合、ループの次の反復はしばらくしてから実行を開始します。

Accept メソッドが nil 以外のエラー値を返さない場合、プログラムは最初の結果値を value 型にラップし、新しい*http.conngoroutine で*http.connこの型の値の serve メソッドを呼び出します。 HTTP リクエスト。

HTTP リクエストに関連する、より派生的な質問:

  • この*http.connタイプの値には、処理の段階を表すいくつかの状態がありますか?
  • 処理で使用されるリーダーとライターは何ですか? また、その役割は何ですか?
  • このプログラムは、カスタム処理関数をどのように呼び出しますか?

5. 思考: HTTP プロトコルに基づいてネットワーク サービス プログラムを正常に停止する方法は?

srv.Shutdown(context.Background()) RegisterOnShutdown でサービスを停止でき、RegisterOnShutdown でサービス停止時の呼び出しを追加できます。

おすすめ

転載: blog.csdn.net/hefrankeleyn/article/details/130033175