Как установить заголовки в HTTP GET запросе на Go?
Правильный способ: используйте клиент и метод Do()
Ваша проблема в том, что вы создаёте объект http.Request с заголовками, но затем вызываете http.Get(url), который создаёт новый запрос без ваших заголовков. В Go нужно использовать подготовленный запрос через клиент и метод Do().
Вот правильное решение:
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://api.example.com/data"
// 1. Создаём запрос
req, err := http.NewRequest("GET", url, nil)
if err != nil {
panic(err)
}
// 2. Устанавливаем заголовки
req.Header.Set("Authorization", "Bearer my-token")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json") // дополнительный заголовок
// 3. Создаём HTTP клиент (можно с таймаутом)
client := &http.Client{}
// 4. Выполняем запрос через клиент
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
// 5. Читаем ответ
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println("Статус:", resp.Status)
fmt.Println("Тело ответа:", string(body))
}
Ключевые моменты:
- Не используйте
http.Get()— это функция-обёртка, которая создаёт запрос "с нуля" и не учитывает ваши заголовки. - Используйте
client.Do(req)— этот метод выполняет подготовленный ранее запрос со всеми заголовками. - Создавайте клиент с таймаутом для production-кода:
&http.Client{Timeout: 10 * time.Second}. - Заголовки чувствительны к регистру в Go — используйте канонические имена (например,
"Content-Type", а не"content-type").
Расширенный пример с обработкой ошибок и таймаутом:
package main
import (
"fmt"
"io"
"net/http"
"time"
)
func main() {
url := "https://api.example.com/data"
// Создаём запрос
req, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Printf("Ошибка создания запроса: %v\n", err)
return
}
// Устанавливаем заголовки
req.Header.Set("Authorization", "Bearer my-token")
req.Header.Set("Content-Type", "application/json")
// Клиент с таймаутом
client := &http.Client{
Timeout: 10 * time.Second,
}
// Выполняем запрос
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Ошибка выполнения запроса: %v\n", err)
return
}
defer resp.Body.Close()
// Читаем тело ответа
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Ошибка чтения ответа: %v\n", err)
return
}
fmt.Printf("Статус: %d\n", resp.StatusCode)
fmt.Printf("Тело: %s\n", body)
}
Почему ваш код не работал?
Функция http.Get(url) внутри делает следующее:
func Get(url string) (resp *Response, err error) {
return DefaultClient.Get(url)
}
А DefaultClient.Get() создаёт новый запрос через http.NewRequest("GET", url, nil) и выполняет его. Все ваши заголовки остаются в первом, неиспользованном запросе.
Используйте client.Do(req) — это единственный правильный способ выполнить кастомный запрос в Go.
Альтернативный подход: использование контекста и middleware
Если вам нужно добавлять одинаковые заголовки к множеству запросов (например, токен авторизации), можно создать функцию-helper или использовать middleware-паттерн.
Пример с функцией-обёрткой:
package main
import (
"fmt"
"io"
"net/http"
"time"
)
// Функция для создания запроса с заголовками
func newRequestWithHeaders(method, url string, headers map[string]string) (*http.Request, error) {
req, err := http.NewRequest(method, url, nil)
if err != nil {
return nil, err
}
for key, value := range headers {
req.Header.Set(key, value)
}
return req, nil
}
func main() {
url := "https://api.example.com/data"
headers := map[string]string{
"Authorization": "Bearer my-token",
"Content-Type": "application/json",
}
req, err := newRequestWithHeaders("GET", url, headers)
if err != nil {
panic(err)
}
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Для более сложных случаев:
Используйте библиотеки вроде github.com/hashicorp/go-retryablehttp или создайте свой HTTP-клиент с переопределением метода Do(). Это удобно, когда нужно логировать запросы, добавлять заголовки или повторять неудачные попытки.
Главное правило: всегда явно создавайте http.Request и выполняйте его через client.Do(), а не используйте http.Get() для кастомных запросов.
Ответов пока нет.
Войдите чтобы оставить ответ