- Home »

Как делать HTTP-запросы в Go — простое руководство
Если вы управляете серверами, создаёте автоматизацию или просто хотите разобраться с тем, как делать HTTP-запросы в Go — эта статья для вас. Go показывает себя как один из самых удобных языков для создания серверного софта, систем мониторинга и автоматизации. Здесь нет лишних зависимостей, огромных фреймворков или сложных конфигураций — только чистый код, который работает быстро и надёжно. Мы разберём всё от простых GET-запросов до сложных POST с кастомными заголовками, обработкой ошибок и таймаутами. Плюс покажем, как интегрировать всё это в ваши скрипты мониторинга и автоматизации.
Основы HTTP-запросов в Go
В Go есть встроенный пакет net/http
, который покрывает 95% потребностей. Никаких дополнительных библиотек не нужно — всё из коробки. Базовая структура выглядит так:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"log"
)
func main() {
resp, err := http.Get("https://httpbin.org/json")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
Основные моменты:
- defer resp.Body.Close() — обязательно закрываем соединение
- Проверка ошибок — Go заставляет обрабатывать ошибки на каждом шаге
- ioutil.ReadAll() — читаем весь response в память
GET-запросы с параметрами
Для более сложных запросов с параметрами используйте url.Values
:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"log"
)
func main() {
baseURL := "https://httpbin.org/get"
params := url.Values{}
params.Add("param1", "value1")
params.Add("param2", "value2")
fullURL := baseURL + "?" + params.Encode()
resp, err := http.Get(fullURL)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
POST-запросы с JSON
POST-запросы требуют немного больше кода, но логика остаётся простой:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"log"
)
type RequestData struct {
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
data := RequestData{
Name: "John Doe",
Email: "john@example.com",
}
jsonData, err := json.Marshal(data)
if err != nil {
log.Fatal(err)
}
resp, err := http.Post("https://httpbin.org/post",
"application/json",
bytes.NewBuffer(jsonData))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
Кастомные заголовки и авторизация
Для работы с API часто нужны кастомные заголовки. Используйте http.NewRequest
:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
"log"
)
func main() {
client := &http.Client{}
req, err := http.NewRequest("GET", "https://httpbin.org/headers", nil)
if err != nil {
log.Fatal(err)
}
// Добавляем заголовки
req.Header.Add("Authorization", "Bearer your-token-here")
req.Header.Add("User-Agent", "MyGoApp/1.0")
req.Header.Add("Accept", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
Таймауты и настройка клиента
По умолчанию Go-клиент может висеть бесконечно. Для production-кода обязательно настройте таймауты:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"time"
"log"
)
func main() {
client := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 100,
IdleConnTimeout: 90 * time.Second,
},
}
resp, err := client.Get("https://httpbin.org/delay/2")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
Обработка ошибок и статус-кодов
Go не считает HTTP 404 или 500 ошибками — нужно проверять статус-коды самостоятельно:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"log"
)
func main() {
resp, err := http.Get("https://httpbin.org/status/404")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
// Проверяем статус-код
if resp.StatusCode != http.StatusOK {
fmt.Printf("Error: received status code %d\n", resp.StatusCode)
return
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
Сравнение с другими языками
Язык | Простота использования | Производительность | Зависимости | Размер бинарника |
---|---|---|---|---|
Go | Высокая | Очень высокая | Встроенные | ~2-10 МБ |
Python (requests) | Очень высокая | Средняя | Внешние | ~50-200 МБ |
Node.js (axios) | Высокая | Средняя | Внешние | ~20-100 МБ |
curl | Средняя | Высокая | Системные | ~1-5 МБ |
Практические кейсы для серверного администрирования
Мониторинг статуса сервисов
package main
import (
"fmt"
"net/http"
"time"
"log"
)
func checkService(url string, ch chan<- string) {
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Get(url)
if err != nil {
ch <- fmt.Sprintf("❌ %s: %v", url, err)
return
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
ch <- fmt.Sprintf("✅ %s: OK (%d)", url, resp.StatusCode)
} else {
ch <- fmt.Sprintf("⚠️ %s: Status %d", url, resp.StatusCode)
}
}
func main() {
services := []string{
"https://google.com",
"https://github.com",
"https://stackoverflow.com",
}
ch := make(chan string, len(services))
for _, service := range services {
go checkService(service, ch)
}
for range services {
fmt.Println(<-ch)
}
}
Webhook-клиент для уведомлений
package main
import (
"bytes"
"encoding/json"
"net/http"
"time"
"log"
)
type SlackMessage struct {
Text string `json:"text"`
}
func sendSlackNotification(webhookURL, message string) error {
msg := SlackMessage{Text: message}
jsonData, err := json.Marshal(msg)
if err != nil {
return err
}
client := &http.Client{Timeout: 15 * time.Second}
resp, err := client.Post(webhookURL, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}
func main() {
webhookURL := "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
message := "🚨 Server load average exceeded 80%"
err := sendSlackNotification(webhookURL, message)
if err != nil {
log.Fatal(err)
}
}
Интеграция с популярными API
Работа с Docker API
package main
import (
"fmt"
"io/ioutil"
"net/http"
"log"
)
func getDockerContainers() {
client := &http.Client{}
req, err := http.NewRequest("GET", "http://localhost:2375/containers/json", nil)
if err != nil {
log.Fatal(err)
}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
func main() {
getDockerContainers()
}
Нестандартные способы использования
Proxy-сервер на Go
package main
import (
"io"
"net/http"
"log"
)
func proxyHandler(w http.ResponseWriter, r *http.Request) {
targetURL := "https://httpbin.org" + r.URL.Path
client := &http.Client{}
req, err := http.NewRequest(r.Method, targetURL, r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Копируем заголовки
for key, values := range r.Header {
for _, value := range values {
req.Header.Add(key, value)
}
}
resp, err := client.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
// Копируем заголовки ответа
for key, values := range resp.Header {
for _, value := range values {
w.Header().Add(key, value)
}
}
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)
}
func main() {
http.HandleFunc("/", proxyHandler)
log.Println("Proxy server running on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Полезные библиотеки
Хотя встроенный net/http
покрывает большинство задач, есть несколько библиотек, которые могут упростить жизнь:
- Resty — более удобный API для HTTP-запросов
- FastHTTP — высокопроизводительная альтернатива net/http
- go-retryablehttp — автоматические повторы запросов
Интересные факты
- Go-программы с HTTP-клиентами компилируются в один бинарник без зависимостей
- Стандартный HTTP-клиент Go автоматически поддерживает HTTP/2
- Connection pooling включён по умолчанию
- Go используется в Docker, Kubernetes, Prometheus — везде, где нужна высокая производительность
Автоматизация и скрипты
Go отлично подходит для создания системных утилит. Для серверного администрирования вы можете:
- Автоматизировать деплой — делать запросы к CI/CD системам
- Мониторить сервисы — проверять health-check эндпоинты
- Интегрироваться с облачными API — AWS, DigitalOcean, etc.
- Создавать webhook-обработчики — получать уведомления от внешних систем
Если вы планируете разворачивать Go-приложения в production, рекомендую рассмотреть VPS-серверы или выделенные серверы с достаточными ресурсами.
Заключение
HTTP-запросы в Go — это просто, быстро и надёжно. Встроенный пакет net/http
покрывает 95% потребностей, а для остальных случаев есть проверенные библиотеки. Главные преимущества Go для серверного администрирования:
- Никаких зависимостей — один бинарник работает везде
- Высокая производительность — отлично подходит для нагруженных систем
- Простота деплоя — скопировал файл и запустил
- Отличная конкурентность — горутины для параллельных запросов
Используйте Go для создания мониторинга, автоматизации деплоя, интеграции с API и везде, где нужна скорость и надёжность. Код получается читаемым, а результат работает быстро и стабильно.
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.