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.Response
Web サービスによって返された応答コンテンツの構造化された表現です。 - 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.Client
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)
// 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.Client
Transport フィールドへの明示的な割り当てがない場合、クライアントは 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.Server
HTTP プロトコルに基づくサーバー、またはネットワーク サービスを表します。
4.1メソッドhttp.Server
の種類ListenAndServe
http.Server
typeListenAndServe
メソッドの機能は、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
このメソッドは、主に次のことを行います。
-
Addr フィールドで現在の
http.Server
タイプの値を確認してください。このフィールドの値は、現在のネットワーク サービスが使用する必要があるネットワーク アドレスを表します。つまり、IP アドレスとポート番号です。このフィールドの値が空の文字列の場合、代わりに ":http" が使用されます。
つまり、このマシンを表すことができる任意のドメイン名と IP アドレスを使用し、ポート番号は 80 です。
-
関数を呼び出して、
net.Listen
決定したネットワークアドレスで TCP プロトコルに基づく監視を開始します。 -
net.Listen
関数が返すエラー値を確認してください。エラー値が nil でない場合は、値を直接返します。それ以外の場合は、現在の値の Serve メソッドを呼び出して、着信 HTTP 要求を受け入れて処理する準備をします。
4.3 (派生問題)net.Listen
関数は何をするのか
net.Listen
関数の機能:
-
パラメータ値に含まれるネットワーク アドレスによって暗示された IP アドレスとポート番号を解析します。
-
与えられたネットワーク プロトコルに従って、監視方法を決定し、監視を開始します。
これは、net.socket 関数とソケット関連の知識にも拡張できます。
4.4 (派生的な質問) http.Server
Serve メソッドの型はどのように HTTP リクエストを受け入れて処理しますか?
for ループでは、ネットワーク監視の Accept メソッドが継続的に呼び出されます。
for {
rw, err := l.Accept()
}
このメソッドは、次の 2 つの結果値を返します。
-
最初の結果値は
net.Conn
、新しい受信 HTTP 要求を含むネットワーク接続を表す型です。 -
2 番目の結果値は、
error
考えられるエラーを表す型の値です。error が nil でない場合、一時的なエラーでない限り、ループは終了します。エラーが一時的なものである場合、ループの次の反復はしばらくしてから実行を開始します。
Accept メソッドが nil 以外のエラー値を返さない場合、プログラムは最初の結果値を value 型にラップし、新しい*http.conn
goroutine で*http.conn
この型の値の serve メソッドを呼び出します。 HTTP リクエスト。
HTTP リクエストに関連する、より派生的な質問:
- この
*http.conn
タイプの値には、処理の段階を表すいくつかの状態がありますか? - 処理で使用されるリーダーとライターは何ですか? また、その役割は何ですか?
- このプログラムは、カスタム処理関数をどのように呼び出しますか?
5. 思考: HTTP プロトコルに基づいてネットワーク サービス プログラムを正常に停止する方法は?
srv.Shutdown(context.Background())
RegisterOnShutdown でサービスを停止でき、RegisterOnShutdown でサービス停止時の呼び出しを追加できます。