Интерфейс http.RoundTripper
Интерфейс http.RoundTripper определяет поведение
объекта, который может выполнить HTTP-запрос и вернуть
ответ. Он содержит один метод RoundTrip, который
принимает указатель на http.Request и возвращает
указатель на http.Response и ошибку. Этот интерфейс
используется в http.Client для выполнения запросов
через транспортный слой.
Синтаксис
type RoundTripper interface {
RoundTrip(req *Request) (*Response, error)
}
Метод RoundTrip выполняет запрос и возвращает ответ.
Важно отметить, что он не должен обрабатывать ответ, например,
читать его тело или закрывать его. Это задача вызывающего кода.
Также метод не должен изменять переданный запрос.
Пример
Самой распространенной реализацией интерфейса является
http.Transport. Давайте создадим транспорт с
настройками и выполним запрос:
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
tr := &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30,
}
client := &http.Client{Transport: tr}
req, err := http.NewRequest("GET", "https://example.com", nil)
if err != nil {
fmt.Println(err)
return
}
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Status: %s\n", res.Status)
fmt.Printf("Body length: %d bytes\n", len(body))
}
Результат выполнения кода:
"Status: 200 OK"
"Body length: 1256 bytes"
Пример
Давайте реализуем собственный тип, удовлетворяющий интерфейсу
http.RoundTripper. Это полезно для логирования запросов
или модификации ответов:
package main
import (
"fmt"
"io"
"net/http"
)
type LoggingRoundTripper struct {
Transport http.RoundTripper
}
func (lrt *LoggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
fmt.Printf("Request: %s %s\n", req.Method, req.URL)
res, err := lrt.Transport.RoundTrip(req)
if err != nil {
fmt.Printf("Error: %v\n", err)
return nil, err
}
fmt.Printf("Response: %s\n", res.Status)
return res, nil
}
func main() {
baseTransport := &http.Transport{}
loggingTransport := &LoggingRoundTripper{
Transport: baseTransport,
}
client := &http.Client{Transport: loggingTransport}
req, err := http.NewRequest("GET", "https://example.com", nil)
if err != nil {
fmt.Println(err)
return
}
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
_, err = io.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
}
Результат выполнения кода:
"Request: GET https://example.com"
"Response: 200 OK"
Пример
Также можно создать транспорт, который модифицирует запросы, например, добавляет заголовки:
package main
import (
"fmt"
"io"
"net/http"
)
type HeaderRoundTripper struct {
Transport http.RoundTripper
Headers map[string]string
}
func (hrt *HeaderRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
newReq := req.Clone(req.Context())
for key, val := range hrt.Headers {
newReq.Header.Set(key, val)
}
return hrt.Transport.RoundTrip(newReq)
}
func main() {
baseTransport := &http.Transport{}
headerTransport := &HeaderRoundTripper{
Transport: baseTransport,
Headers: map[string]string{
"User-Agent": "MyCustomClient/1.0",
"X-Custom-Head": "test",
},
}
client := &http.Client{Transport: headerTransport}
req, err := http.NewRequest("GET", "https://httpbin.org/headers", nil)
if err != nil {
fmt.Println(err)
return
}
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}
Результат выполнения кода:
"{\n \"headers\": {\n \"Host\": \"httpbin.org\",\n \"User-Agent\": \"MyCustomClient/1.0\",\n \"X-Custom-Head\": \"test\"\n }\n}"
Смотрите также
-
тип
http.Transport,
который является стандартной реализацией интерфейса -
структуру
http.Client,
которая использует интерфейс для выполнения запросов -
функцию
http.NewRequest,
которая создает новый HTTP-запрос -
тип
http.Request,
который представляет HTTP-запрос