首頁  >  文章  >  後端開發  >  golang 封裝 http請求

golang 封裝 http請求

PHPz
PHPz原創
2023-05-11 12:00:07614瀏覽

隨著網路的發展,HTTP請求已經成為了後端開發的標配,也是前端發起網路請求的方式。在Golang中,標準函式庫內建了net/http套件,提供了一個完整的HTTP客戶端和服務端。不過,封裝一個HTTP請求庫能夠讓我們在開發過程中更有效率、方便地發起HTTP請求。在這篇文章中,我們將討論如何封裝一個Golang的HTTP請求函式庫。

一、需求分析

在封裝一個HTTP請求庫之前,我們需要明確一些需求和功能,以便於更好地設計和開發我們的庫。在這裡,我們認為一個完整的HTTP請求庫需要具備以下幾個功能:

  1. 支援GET、POST、PUT、DELETE等HTTP方法。
  2. 支援設定請求頭、請求體以及請求參數。
  3. 支援設定逾時時間和重試次數。
  4. 支援傳回值的格式化成不同的資料類型。

基於上述需求和功能,我們可以開始設計和開發我們的HTTP請求庫。

二、設計與實作

2.1 設計要點

在設計我們的HTTP請求函式庫時,我們需要考慮一些關鍵點,以便於實現一個高可用、可擴充和易於使用的請求庫。具體來說,我們應該考慮以下幾個面向:

  1. 網路問題。

在發起HTTP請求時,我們要考慮網路問題,例如連線逾時、請求逾時等等。因此,在我們的HTTP請求庫中需要支援設定連線逾時時間和請求逾時時間。

  1. 異常處理。

當我們發起HTTP請求時,可能會出現各種不可預測的異常,例如網路異常、回傳值異常等等。為了讓我們的HTTP請求庫更加健壯,需要針對這些異常進行處理,例如根據http狀態碼、異常資訊等來進行對應的處理。

  1. RESTful API支援。

在RESTful API中,常常需要提交JSON資料或表單資料等等。因此,在我們的HTTP請求庫中,需要支援這些資料的提交和解析。

  1. 對傳回值的處理。

在發起HTTP請求後,我們需要處理回傳值。通常,不同的API介面傳回值的格式可能會有所不同,因此,我們需要支援根據API介面的回傳值格式進行對應的處理。

2.2 實作流程

基於以上的設計要點,當我們開始實作HTTP請求庫時,我們可以按照以下步驟進行:

  1. 定義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
}
  1. #發起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
}

使用http.Transport中的DialContext()方法來設定連線逾時和請求逾時:

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()
  1. 異常處理。

在發起HTTP請求時,可能會出現各種不可預測的異常,例如網路異常、回傳值異常等等。因此,在我們的HTTP請求庫中需要針對這些異常進行處理。

例如,我們可以根據HTTP的status code 和 response body 來檢查HTTP請求的例外。如果發生了異常,我們可以根據異常的類型傳回相應的錯誤訊息,以便於在開發過程中及時發現並進行處理。

  1. RESTful API支援。

在呼叫RESTful API時,我們需要支援不同的提交格式,例如JSON資料或表單資料等等。為了讓我們的HTTP請求庫更通用,可以新增一個ContentType屬性欄位來支援不同的提交格式。同時,在提交JSON資料時,我們也需要將資料編碼為JSON格式。

  1. 對傳回值的處理。

在呼叫介面後,我們需要對回傳值進行處理。通常,不同的API介面傳回值的格式可能會有所不同,因此,我們需要在上層應用中根據API介面的回傳值格式進行對應的處理。例如,可以根據傳回值的格式設定反序列化的方式。

2.3 程式碼實作

基於以上的設計要點,當我們開始實作HTTP請求函式庫時,可以參考以下的程式碼實作:

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

三、總結

透過以上的討論,我們可以發現,封裝一個Golang的HTTP請求庫並不是一件特別困難的事。關鍵在於我們應該清楚我們的需求、了解網路請求的一些細節,然後我們就可以在Golang中使用標準函式庫提供的方法來封裝一個優秀的HTTP請求庫了。同時,在實作的過程中,我們也需要考慮一些細節問題,例如異常處理、RESTful API支援、對傳回值的處理等等。透過認真的設計和實現,我們可以開發一個高品質的HTTP請求庫,使我們的Golang開發更有效率和便利。

以上是golang 封裝 http請求的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn