Home > Backend Development > Golang > golang encapsulates http requests

golang encapsulates http requests

PHPz
Release: 2023-05-11 12:00:07
Original
635 people have browsed it

With the development of the Internet, HTTP requests have become the standard for back-end development and are also the way for the front-end to initiate network requests. In Golang, the standard library has a built-in net/http package, providing a complete HTTP client and server. However, encapsulating an HTTP request library allows us to initiate HTTP requests more efficiently and conveniently during the development process. In this article, we will discuss how to encapsulate a Golang HTTP request library.

1. Requirements Analysis

Before encapsulating an HTTP request library, we need to clarify some requirements and functions in order to better design and develop our library. Here, we believe that a complete HTTP request library needs to have the following functions:

  1. Supports HTTP methods such as GET, POST, PUT, and DELETE.
  2. Supports setting request headers, request bodies and request parameters.
  3. Supports setting timeout and retry times.
  4. Supports the formatting of return values ​​into different data types.

Based on the above requirements and functions, we can start to design and develop our HTTP request library.

2. Design and Implementation

2.1 Design Points

When designing our HTTP request library, we need to consider some key points in order to achieve a highly available and reliable Extensible and easy-to-use requests library. Specifically, we should consider the following aspects:

  1. Network issues.

When initiating an HTTP request, we must consider network problems, such as connection timeout, request timeout, etc. Therefore, our HTTP request library needs to support setting the connection timeout and request timeout.

  1. Exception handling.

When we initiate an HTTP request, various unpredictable exceptions may occur, such as network exceptions, return value exceptions, etc. In order to make our HTTP request library more robust, these exceptions need to be handled, for example, based on http status codes, exception information, etc.

  1. RESTful API support.

In RESTful API, it is often necessary to submit JSON data or form data, etc. Therefore, in our HTTP request library, we need to support the submission and parsing of these data.

  1. Handling of return values.

After initiating the HTTP request, we need to process the return value. Generally, the format of the return value of different API interfaces may be different. Therefore, we need to support corresponding processing according to the return value format of the API interface.

2.2 Implementation process

Based on the above design points, when we start to implement the HTTP request library, we can follow the following steps:

  1. Define the HTTP request Structure.

When encapsulating an HTTP request library, we need to encapsulate the HTTP request information. Specifically, we can define a structure of an HTTP request to store and transfer the information required for the HTTP request. The following is an example of the structure of an HTTP request:

type Request struct {
    URL        string
    Method     string
    Headers    map[string]string
    Body       []byte
    Params     map[string]string
    Timeout    int
    RetryTimes int
}
Copy after login
  1. Initiates an HTTP request.

After we define the HTTP request structure, we can send HTTP requests through Golang's standard library.

For example, we can use the http.NewRequest() method to create an HTTP request:

req, err := http.NewRequest(req.Method, req.URL, bytes.NewBuffer(req.Body))
if err != nil {
    return nil, err
}
Copy after login

Use the DialContext() method in http.Transport to set the connection timeout and request timeout:

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,
        }
    }
Copy after login

Next, we can use the Do() method to initiate an HTTP request and get the return value:

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

After successfully initiating the HTTP request, we need to release resources to avoid memory leaks caused by malicious requests:

defer resp.Body.Close()
Copy after login
  1. Exception handling.

When initiating an HTTP request, various unpredictable exceptions may occur, such as network exceptions, return value exceptions, etc. Therefore, these exceptions need to be handled in our HTTP request library.

For example, we can check HTTP request exceptions based on HTTP status code and response body. If an exception occurs, we can return corresponding error information according to the type of exception, so that it can be discovered and processed in time during the development process.

  1. RESTful API support.

When calling RESTful API, we need to support different submission formats, such as JSON data or form data, etc. To make our HTTP request library more versatile, a ContentType attribute field can be added to support different submission formats. At the same time, when submitting JSON data, we also need to encode the data into JSON format.

  1. Handling of return values.

After calling the interface, we need to process the return value. Generally, the format of the return value of different API interfaces may be different. Therefore, we need to perform corresponding processing in the upper-layer application according to the return value format of the API interface. For example, you can set the deserialization method based on the format of the return value.

2.3 Code Implementation

Based on the above design points, when we start to implement the HTTP request library, we can refer to the following code implementation:

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)
}
Copy after login

3. Summary

Through the above discussion, we can find that encapsulating a Golang HTTP request library is not a particularly difficult task. The key is that we should be clear about our needs and understand some details of network requests, and then we can use the methods provided by the standard library to encapsulate an excellent HTTP request library in Golang. At the same time, during the implementation process, we also need to consider some details, such as exception handling, RESTful API support, processing of return values, etc. Through careful design and implementation, we can develop a high-quality HTTP request library to make our Golang development more efficient and convenient.

The above is the detailed content of golang encapsulates http requests. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template