Как стать автором
Обновить

Golang RoundTripper

Уровень сложностиПростой

Привет, сегодня мы рассмотрим функционал 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
Мой телеграм канал

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.