ホームページ  >  記事  >  バックエンド開発  >  golang は http リクエストをカプセル化します

golang は http リクエストをカプセル化します

PHPz
PHPzオリジナル
2023-05-11 12:00:07614ブラウズ

インターネットの発展に伴い、HTTP リクエストはバックエンド開発の標準となり、フロントエンドがネットワーク リクエストを開始する方法でもあります。 Golang では、標準ライブラリに net/http パッケージが組み込まれており、完全な HTTP クライアントとサーバーを提供します。ただし、HTTP リクエスト ライブラリをカプセル化すると、開発プロセス中に HTTP リクエストをより効率的かつ便利に開始できるようになります。この記事では、Golang HTTP リクエスト ライブラリをカプセル化する方法について説明します。

1. 要件分析

HTTP リクエスト ライブラリをカプセル化する前に、ライブラリをより適切に設計および開発するために、いくつかの要件と機能を明確にする必要があります。ここでは、完全な HTTP リクエスト ライブラリには次の機能が必要であると考えています。

  1. GET、POST、PUT、DELETE などの HTTP メソッドをサポートします。
  2. リクエスト ヘッダー、リクエスト本文、リクエスト パラメーターの設定をサポートします。
  3. タイムアウト時間と再試行時間の設定をサポートします。
  4. 戻り値のさまざまなデータ型へのフォーマットをサポートします。

上記の要件と機能に基づいて、HTTP リクエスト ライブラリの設計と開発を開始できます。

2. 設計と実装

2.1 設計ポイント

HTTP リクエスト ライブラリを設計するときは、可用性と信頼性の高い拡張機能を実現するために、いくつかの重要なポイントを考慮する必要があります。使いやすいリクエスト ライブラリ。具体的には、次の側面を考慮する必要があります:

  1. ネットワークの問題。

HTTP リクエストを開始するときは、接続タイムアウトやリクエスト タイムアウトなどのネットワークの問題を考慮する必要があります。したがって、HTTP リクエスト ライブラリは、接続タイムアウトとリクエスト タイムアウトの設定をサポートする必要があります。 #########例外処理。

  1. HTTP リクエストを開始すると、ネットワーク例外、戻り値例外など、さまざまな予期しない例外が発生する可能性があります。 HTTP リクエスト ライブラリをより堅牢にするために、これらの例外は、たとえば http ステータス コードや例外情報などに基づいて処理される必要があります。
#RESTful API のサポート。

    RESTful APIでは、JSONデータやフォームデータなどを送信する必要があることがよくあります。したがって、HTTP リクエスト ライブラリでは、これらのデータの送信と解析をサポートする必要があります。
戻り値の処理。

    HTTP リクエストを開始した後、戻り値を処理する必要があります。一般に、API インターフェースごとに戻り値の形式が異なる場合があるため、API インターフェースの戻り値形式に応じた処理をサポートする必要があります。
  1. 2.2 実装プロセス

上記の設計ポイントに基づいて、HTTP リクエスト ライブラリの実装を開始するときは、次の手順に従うことができます。 HTTP リクエストの構造。

HTTP リクエスト ライブラリをカプセル化する場合、HTTP リクエスト情報をカプセル化する必要があります。具体的には、HTTP リクエストに必要な情報を保存および転送するための HTTP リクエストの構造を定義できます。以下は、HTTP リクエストの構造の例です。

type Request struct {
    URL        string
    Method     string
    Headers    map[string]string
    Body       []byte
    Params     map[string]string
    Timeout    int
    RetryTimes int
}

    HTTP リクエストを開始します。
HTTP リクエスト構造を定義した後、Golang の標準ライブラリを通じて HTTP リクエストを送信できます。

たとえば、http.NewRequest() メソッドを使用して HTTP リクエストを作成できます。
    req, err := http.NewRequest(req.Method, req.URL, bytes.NewBuffer(req.Body))
    if err != nil {
        return nil, err
    }
  1. http.Transport の DialContext() メソッドを使用して、接続タイムアウトとリクエスト タイムアウトを設定します。 :
  2. client := &http.Client{
            Transport: &http.Transport{
                DialContext: (&net.Dialer{
                    Timeout:   time.Duration(req.Timeout) * time.Second,
                    KeepAlive: time.Duration(req.Timeout) * time.Second,
                }).DialContext,
                MaxIdleConns:        100,              // http.ConnectionPool数量
                IdleConnTimeout:     90 * time.Second, // http.ConnectionPool中连接的空闲超时时间
                TLSHandshakeTimeout: 10 * time.Second,
                ExpectContinueTimeout: 1 * time.Second,
            }
        }
次に、Do() メソッドを使用して HTTP リクエストを開始し、戻り値を取得します。

resp, err := client.Do(req)
if err != nil {
    return nil, err
}

HTTP リクエストが正常に開始された後、リソースを解放する必要があります。悪意のあるリクエストによって引き起こされるメモリ リーク:

defer resp.Body.Close()

例外処理。

HTTP リクエストを開始すると、ネットワーク例外、戻り値例外など、さまざまな予期しない例外が発生する可能性があります。したがって、これらの例外は HTTP リクエスト ライブラリで処理する必要があります。

たとえば、HTTP ステータス コードと応答本文に基づいて HTTP リクエストの例外を確認できます。例外が発生した場合、例外の種類に応じて対応するエラー情報を返すことができるため、開発プロセス中に適切なタイミングで例外を発見して処理できます。
  1. #RESTful API のサポート。

RESTful API を呼び出す場合、JSON データやフォーム データなどのさまざまな送信形式をサポートする必要があります。 HTTP リクエスト ライブラリの汎用性を高めるために、ContentType 属性フィールドを追加して、さまざまな送信形式をサポートできます。同時に、JSON データを送信する場合は、データを JSON 形式にエンコードする必要もあります。

戻り値の処理。
  1. インターフェースを呼び出した後、戻り値を処理する必要があります。一般に、APIインターフェースごとに戻り値の形式が異なる場合があるため、上位アプリケーションではAPIインターフェースの戻り値形式に応じた処理を行う必要があります。たとえば、戻り値の形式に基づいて逆シリアル化メソッドを設定できます。

2.3 コード実装

    上記の設計ポイントに基づいて、HTTP リクエスト ライブラリの実装を開始するときは、次のコード実装を参照できます:
  1. package httpreq
    
    import (
        "bytes"
        "encoding/json"
        "io/ioutil"
        "net"
        "net/http"
        "time"
    )
    
    type Request struct {
        URL        string
        Method     string
        Headers    map[string]string
        Body       []byte
        Params     map[string]string
        Timeout    int
        RetryTimes int
        ContentType string
    }
    
    type Response struct {
        StatusCode int
        Body       []byte
    }
    
    func Do(req Request) (*Response, error) {
        if req.Method == "" {
            req.Method = http.MethodGet
        }
    
        // 处理请求参数
        if req.Params != nil {
            req.URL = AddQueryParams(req.URL, req.Params)
        }
    
        // 创建一个请求
        httpRequest, err := http.NewRequest(req.Method, req.URL, bytes.NewBuffer(req.Body))
        if err != nil {
            return nil, err
        }
    
        // 处理请求头
        if req.Headers != nil {
            for k, v := range req.Headers {
                httpRequest.Header.Set(k, v)
            }
        }
    
        // 设置ContentType
        if req.ContentType != "" {
            httpRequest.Header.Set("Content-Type", req.ContentType)
        }
    
        // 设置请求超时
        httpClient := &http.Client{
            Transport: &http.Transport{
                DialContext: (&net.Dialer{
                    Timeout:   time.Duration(req.Timeout) * time.Second,
                    KeepAlive: time.Duration(req.Timeout) * time.Second,
                }).DialContext,
                MaxIdleConns:        100,              // http.ConnectionPool数量
                IdleConnTimeout:     90 * time.Second, // http.ConnectionPool中连接的空闲超时时间
                TLSHandshakeTimeout: 10 * time.Second,
                ExpectContinueTimeout: 1 * time.Second,
            },
        }
    
        // 发起请求
        resp, err := httpClient.Do(httpRequest)
        if err != nil {
            return nil, err
        }
    
        defer resp.Body.Close()
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            return nil, err
        }
    
        // 处理异常
        if resp.StatusCode >= 400 {
            return nil, NewError(resp.StatusCode, body)
        }
    
        return &Response{StatusCode: resp.StatusCode, Body: body}, nil
    }
    
    func AddQueryParams(url string, params map[string]string) string {
        var queryParams string
        for k, v := range params {
            queryParams = queryParams + "&" + k + "=" + v
        }
        url = url + "?" + queryParams[1:]
        return url
    }
    
    func NewError(statusCode int, body []byte) error {
        errorMsg := string(body)
        if errorMsg == "" {
            errorMsg = http.StatusText(statusCode)
        }
        return &httpError{StatusCode: statusCode, Message: errorMsg}
    }
    
    type httpError struct {
        StatusCode int
        Message    string
    }
    
    func (e *httpError) Error() string {
        return e.Message
    }
    
    func (r *Response) BindJSON(v interface{}) error {
        return json.Unmarshal(r.Body, v)
    }
    
    func (r *Response) BindText() string {
        return string(r.Body)
    }
  2. 3。まとめ###

    上記の議論を通じて、Golang HTTP リクエスト ライブラリのカプセル化は特に難しい作業ではないことがわかります。重要なのは、ニーズを明確にし、ネットワーク リクエストの詳細を理解する必要があることです。そうすれば、標準ライブラリによって提供されるメソッドを使用して、優れた HTTP リクエスト ライブラリを Golang でカプセル化できるようになります。同時に、実装プロセス中に、例外処理、RESTful API のサポート、戻り値の処理などの詳細についても考慮する必要があります。慎重な設計と実装を通じて、高品質の HTTP リクエスト ライブラリを開発し、Golang 開発をより効率的かつ便利にすることができます。

以上がgolang は http リクエストをカプセル化しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。