Go HTTP 클라이언트에 미들웨어 추가

5698 단어 go
Go 표준 라이브러리는 HTTP 요청을 위한 환상적인 지원을 제공합니다. 그러나 때때로 요청을 수정해야 하거나 응답 시 조치를 취해야 합니다(예: 응답 로깅).

대부분의 경우 모든 요청에 ​​이러한 로그를 추가하면 많은 중복 코드가 포함됩니다. 다른 경우에는 다른 패키지 또는 타사 라이브러리의 제한된 액세스로 인해 클라이언트에 액세스하지 못할 수 있습니다. 그래서 RoundTrippers을 소개합니다.

RoundTripper는 http 클라이언트에 추가할 수 있으며 http 트랜잭션을 실행하여 요청을 검사 및 수정하고 응답을 검사 및 수정할 수 있습니다.

RoundTripper는 http 클라이언트 전송에서 설정할 수 있습니다. 인터페이스는 다음과 같습니다.

type RoundTripper interface {
    RoundTrip(*http.Request) (*http.Response, error)
}



그리고 RoundTripper는 다음과 같이 클라이언트에 설정됩니다.

client := &http.Client{
    Transport: myRoundTripper,
}



http.Client는 클라이언트 전송이 DefaultTransport인 경우 nil로 확인됩니다. RoundTrippers를 미들웨어로 연결하는 것은 매우 쉽습니다. DefaultTransport 라운드 트리퍼는 편리한 기본값과 함께 제공되므로 기본으로 간주해야 합니다.

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



이제 기본 사항을 다루었으므로 웹 서버 미들웨어에 적용된 Philipp from GoWebExamples.com에서 처음 본 단일 연결 예를 사용할 수 있습니다. 이해하기 쉬운 간단한 작은 패턴입니다.

// internalRoundTripper is a holder function to make the process of
// creating middleware a bit easier without requiring the consumer to
// implement the RoundTripper interface.
type internalRoundTripper func(*http.Request) (*http.Response, error)

func (rt internalRoundTripper) RoundTrip(req *http.Request)
                                            (*http.Response, error) {
    return rt(req)
}

// Middleware is our middleware creation functionality.
type Middleware func(http.RoundTripper) http.RoundTripper

// Chain is a handy function to wrap a base RoundTripper (optional)
// with the middlewares.
func Chain(rt http.RoundTripper, middlewares ...Middleware)
                                                    http.RoundTripper {
    if rt == nil {
        rt = http.DefaultTransport
    }

    for _, m := range middlewares {
        rt = m(rt)
    }

    return rt
}



여기에서 요구 사항에 맞는 사용자 정의 미들웨어를 작성하는 것은 간단합니다. 아래 두 가지 예:
  • CustomTimer는 RoundTrip이 완료된 후 함수를 실행하고 이후 시간을 표시합니다. 이것은 요청이 이루어지기 전에 작업이 어떻게 발생할 수 있는지 보여줍니다. 이 경우 시작 시간을 캡처한 다음 defer 를 사용하여 요청이 이루어진 후 코드를 실행합니다.
  • DumpResponse는 응답 본문을 stdout에 인쇄합니다. CustomTimer와 유사하게 지연은 요청이 이루어진 후 덤프를 실행하는 데 사용됩니다. 여기서 차이점은 명명된 응답이 응답 데이터에 액세스하는 데 사용된다는 것입니다.

  • // CustomTimer takes a writer and will output a request duration.
    func CustomTimer(w io.Writer) Middleware {
        return func(rt http.RoundTripper) http.RoundTripper {
            return internalRoundTripper(func(req *http.Request)
                                                (*http.Response, error) {
                startTime := time.Now()
                defer func() {
                    fmt.Fprintf(w, ">>> request duration: %s",
                        time.Since(startTime))
                }()
    
                return rt.RoundTrip(req)
            })
        }
    }
    
    // DumpResponse uses dumps the response body to console.
    func DumpResponse(includeBody bool) Middleware {
        return func(rt http.RoundTripper) http.RoundTripper {
            return internalRoundTripper(func(req *http.Request)
                                        (resp *http.Response, err error) {
                defer func() {
                    if err == nil {
                        o, err := httputil.DumpResponse(resp, includeBody)
                        if err != nil {
                            panic(err)
                        }
    
                        fmt.Println(string(o))
                    }
                }()
    
                return rt.RoundTrip(req)
            })
        }
    }
    
    


    필요에 맞는 미들웨어를 작성했으면 http.Client 를 생성하고 Transport 를 설정하는 것만큼 쉽게 HTTP 클라이언트에 미들웨어를 추가할 수 있습니다.

    client := http.Client{
        // Using the Chain function, we can add middlewares to our base
        // RoundTripper. These middlewares will run on every http request. 
        Transport: Chain(nil, CustomTimer(os.Stdout), DumpResponse(false)),
    }
    
    // Start making requests
    _, err := client.Get("http://jonfriesen.ca")
    if err != nil {
        panic(err)
    }
    
    


    RoundTripper 미들웨어의 또 다른 유용한 용도는 타사 클라이언트 내에서입니다. 예를 들어 GitHub Go 라이브러리는 요청에 헤더를 추가하는 기능을 기본적으로 지원하지 않습니다. 타사 클라이언트가 http.Client 설정을 지원하는 것이 일반적입니다. 예를 들면 다음과 같습니다.

    // AddHeader adds a header to the request.
    func AddHeader(key, value string) Middleware {
        return func(rt http.RoundTripper) http.RoundTripper {
            return internalRoundTripper(func(req *http.Request)
                                                (*http.Response, error) {
                header := req.Header
                if header == nil {
                    header = make(http.Header)
                }
    
                header.Set(key, value)
    
                return rt.RoundTrip(req)
            })
        }
    }
    
    func main() {
        userClient := github.NewClient(&http.Client{
            Transport: Chain(nil, AddHeader("key", "value")),
        })
    }
    
    

    좋은 웹페이지 즐겨찾기