Pull to refresh

Golang RoundTripper

Level of difficultyEasy

Привет, сегодня мы рассмотрим функционал HTTP Round Tripper в стандартной библиотеке Go. Этот функционал позволяет улучшить работу с HTTP клиентами и написать более эффективный и автоматизированный код.

Давайте начнем с простых примеров. В основном, для создания HTTP запроса мы используем http.Client. Который выглядит следующим образом

type Client struct {
	Transport RoundTripper 
	CheckRedirect func(req *Request, via []*Request) error
	Jar CookieJar
	Timeout time.Duration
}

Сегодня мы рассмотрим интерфейс Round Tripper, который представляет собой более низкоуровневую абстракцию для отправки HTTP запросов и получения ответов.

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

Интерфейс Round Tripper содержит всего один метод - RoundTrip, который выполняет одну транзакцию HTTP и возвращает ответ и ошибку. Мы можем настраивать Round Tripper для различных целей, например, для логирования запросов и ответов, повторной отправки запросов при ошибке, управления аутентификацией и иных других действий до или после запроса. Далее приведены базовые примеры использования.

Базовый пример логирующего

type loggingRoundTripper struct {
    next                http.RoundTripper
    logger              io.Writer
}

// RoundTrip декоратор дефолтного RoundTripper
func (l loggingRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
  // логирование зарпроса 
  fmt.Fprintf(l.logger, "[%s] %s %s\n", time.Now().Format(time.ANSIC), r.Method, r.URL.String())
	
  resp, err := l.next.RoundTrip(r)

  // логирование ответа
  fmt.Fprintf(l.logger, "[%s] %s %s %d\n", time.Now().Format(time.ANSIC), r.Method, r.URL.String(), resp.StatusCode)
  return resp, err
}

Базовый пример для ретрай логики

type retryRoundTripper struct {
	next       http.RoundTripper
	maxRetries int
	delay      time.Duration
}

func (rr retryRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
	var res *http.Response
	var err error
	for attempts := 0; attempts < rr.maxRetries; attempts++ {
		res, err = rr.next.RoundTrip(r)
		// good outcome
		if err == nil && res.StatusCode < http.StatusInternalServerError {
			break
		}
		
		// delay and retry
		select {
		case <-r.Context().Done():
			return res, r.Context().Err()
		case <-time.After(rr.delay):
		}
	}

	return res, err
}

Базовый пример для логики авторизации

type authRoundTripper struct {
	next      http.RoundTripper
	user, pwd string
}

func (a authRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
	r.SetBasicAuth(a.user, a.pwd)
	return a.next.RoundTrip(r)
}

После чего на основании данных RoundTripper можно иницализировать HTTP клиент

c := &http.Client{
		Transport: &authRoundTripper{
			next: &retryRoundTripper{
				next: &loggingRoundTripper{
					next:   http.DefaultTransport,
					logger: os.Stdout,
				},
				maxRetries: maxRetrieNum,
				delay:      delayDuration,
			},
			user: "user",
			pwd:  "pwd",
		},
	}

В общем, Round Tripper представляет собой мощный инструмент для настройки HTTP клиентов в Go, который позволяет улучшить их функциональность и эффективность. Применить данный инструмент можно для элегантного решения множества задач. В своем рабочем проекте получилось достаточно элегантно реализовать Round Tripper для авторизации посредством JWT, c перелоогином в случае когда токен перестал быть валидным. Возможно в ваших проектах вы найдете какое либо более интересное применение.

Надеюсь, эти примеры помогли вам лучше понять его возможности и применение.

Doc RoundTripper
Мой телеграм канал

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.