Гид по технологиям

HTTP-запросы в Go: как отправлять GET, POST, PUT и DELETE

6 min read Go Обновлено 11 Apr 2026
HTTP-запросы в Go — GET, POST, PUT, DELETE
HTTP-запросы в Go — GET, POST, PUT, DELETE

Иллюстрация: талисман Go (гофер) и иконка глобуса со стрелками передачи данных между ними.

Что в двух словах означает HTTP-запрос

HTTP — протокол приложения для обмена запросами и ответами между клиентом (браузером или программой) и сервером. Запрос содержит метод (GET, POST и т.д.), URL ресурса, заголовки и опциональное тело. Методы отражают CRUD: GET — чтение, POST — создание, PUT — обновление, DELETE — удаление.

Определение термина: HTTP-запрос — структурированное сообщение, которое клиент отправляет серверу с намерением получить или изменить ресурс.

Важно: PUT и PATCH часто используются для обновления; PUT обычно ожидает полное представление ресурса, PATCH — частичное.

Почему именно Go и пакет net/http

Пакет net/http — стандартная библиотека Go для HTTP. Он предоставляет всё необходимое: создание серверов, формирование запросов, управление клиентом и обработку ответов. Большинство web-фреймворков на Go строятся поверх этого пакета.

Преимущества:

  • Стандартная реализация, поддерживаемая сообществом.
  • Простая интеграция с контекстом (context.Context) и таймаутами.
  • Высокая производительность и хорошая читаемость кода.

Замечание: для упрощённых вызовов можно использовать http.Get и http.Post, но для контроля заголовков, таймаутов и тела предпочтительнее http.NewRequest + http.Client.

Шаблон: как формируется HTTP-запрос в Go

  1. Создаём URL и тело запроса (если нужно).
  2. Формируем request := http.NewRequest(method, url, body).
  3. Устанавливаем заголовки request.Header.Set(…).
  4. Создаём клиента client := &http.Client{Timeout: …} при необходимости.
  5. Отправляем response, err := client.Do(request).
  6. Читаем response.Body через io.ReadAll и закрываем body (defer response.Body.Close()).
  7. Обрабатываем статус и тело.

Совет: всегда задавайте таймауты в http.Client, чтобы избежать зависших соединений.

POST: пример создания ресурса

Ниже функция createUser отправляет POST на https://reqres.in/api/users для создания пользователя. Код сохранён из примера и показывает базовый цикл: построение запроса, отправка, чтение ответа и форматирование JSON.

package main  
  
import (  
    "bytes"  
    "encoding/json"  
    "fmt"  
    "io"  
    "net/http"  
)  
  
func createUser(name, job string) {  
    fmt.Println("Creating user...")  
  
    apiUrl := "https://reqres.in/api/users"  
    userData := []byte(`{"name":"` + name + `","job":"` + job + `"}`)  
  
    // create new http request  
    request, error := http.NewRequest("POST", apiUrl, bytes.NewBuffer(userData))  
    request.Header.Set("Content-Type", "application/json; charset=utf-8")  
  
    // send the request  
    client := &http.Client{}  
    response, error := client.Do(request)  
  
    if error != nil {  
        fmt.Println(error)  
    }  
  
    responseBody, error := io.ReadAll(response.Body)  
  
    if error != nil {  
        fmt.Println(error)  
    }  
  
    formattedData := formatJSON(responseBody)  
    fmt.Println("Status: ", response.Status)  
    fmt.Println("Response body: ", formattedData)  
  
    // clean up memory after execution  
    defer response.Body.Close()  
}  

Функция formatJSON форматирует байтовый массив JSON для удобного чтения:

// function to format JSON data  
func formatJSON(data []byte) string {  
    var out bytes.Buffer  
    err := json.Indent(&out, data, "", "  ")  
  
    if err != nil {  
        fmt.Println(err)  
    }  
  
    d := out.Bytes()  
    return string(d)  
}  

Вызывается так:

func main() {  
    fmt.Println("Making POST request...")  
    createUser("Tim Omolana", "Writer")  
}  

Вывод в терминале (пример):

Пример вывода программы с POST-запросом в терминале

Важно: всегда закрывайте response.Body вызовом defer response.Body.Close() сразу после проверки ошибки, чтобы избежать утечек соединений.

GET: получение ресурса

GET-запрос не содержит тела. Пример функции getUser, которая получает пользователя по id:

// main.go  
func getUser(id string) {  
    fmt.Println("Getting user by ID...")  
  
    // make GET request to API to get user by ID  
    apiUrl := "https://reqres.in/api/users/" + id  
    request, error := http.NewRequest("GET", apiUrl, nil)  
  
    if error != nil {  
        fmt.Println(error)  
    }  
  
    request.Header.Set("Content-Type", "application/json; charset=utf-8")  
  
    client := &http.Client{}  
    response, error := client.Do(request)  
  
    if error != nil {  
        fmt.Println(error)  
    }  
  
    responseBody, error := io.ReadAll(response.Body)  
  
    if error != nil {  
        fmt.Println(error)  
    }  
  
    formattedData := formatJSON(responseBody)  
    fmt.Println("Status: ", response.Status)  
    fmt.Println("Response body: ", formattedData)  
  
    // clean up memory after execution  
   defer response.Body.Close()  
}  

Пример вызова:

func main() {  
    fmt.Println("Making GET request...")  
    getUser("2")  
}  

Пример вывода программы с GET-запросом в терминале

Замечание: для запросов с параметрами используйте net/url для безопасного кодирования query-параметров.

PUT: обновление ресурса

PUT похож на POST, но обычно обновляет существующий ресурс и требует указания идентификатора в URL.

// main.go  
func updateUser(name, job, id string) {  
    fmt.Println("Updating user...")  
  
    // make PUT request to API to update user  
    apiUrl := "https://reqres.in/api/users/" + id  
    userData := []byte(`{"name":"` + name + `","job":"` + job + `"}`)  
  
    // create new http PUT request  
    request, error := http.NewRequest("PUT", apiUrl, bytes.NewBuffer(userData))  
    request.Header.Set("Content-Type", "application/json; charset=utf-8")  
  
    // Remaining function body from createUser function...  
    // Make request, get response, and clear memory...  
}  

Пример вызова:

func main() {  
    // update entry with the ID 2.  
    updateUser("Tim Newname", "Staff Writer", "2")  
}  

Пример вывода программы с PUT-запросом в терминале

Совет: при частичных обновлениях используйте PATCH (если API поддерживает). PUT чаще подразумевает замену всего ресурса.

DELETE: удаление ресурса

DELETE удаляет ресурс по URI. Ответ часто содержит только статус (без тела).

func deleteUser(id string) {  
    fmt.Println("Deleting user...")  
    // make DELETE request to API to delete user  
    apiUrl := "https://reqres.in/api/users/" + id  
  
    // create new http request  
    request, error := http.NewRequest("DELETE", apiUrl, nil)  
    request.Header.Set("Content-Type", "application/json; charset=utf-8")  
  
    client := &http.Client{}  
    response, error := client.Do(request)  
    if error != nil {  
        fmt.Println(error)  
    }  
  
    fmt.Println("Status: ", response.Status)  
}  

Вызов:

func main() {  
    fmt.Println("Making DELETE request...")  
    deleteUser("2")  
}  

Пример вывода программы с DELETE-запросом в терминале

Важно: некоторые API на DELETE возвращают тело с подтверждением, другие — только статус 204 No Content.

Упрощённые методы: http.Get и http.Post

Для быстрых запросов можно использовать:

  • http.Get(url) — выполняет GET и возвращает response, err
  • http.Post(url, contentType, body) — выполняет POST

Они удобны, но дают меньше контроля (заголовки, таймауты, кастомные клиентские настройки). Для продакшена предпочтительнее http.NewRequest с настраиваемым http.Client.

Шаблон безопасности и обработки ошибок

Important: всегда проверяйте ошибки после каждой сетевой операции и закрывайте response.Body.

Рекомендации по безопасности:

  • Используйте HTTPS везде, где это возможно.
  • Валидируйте и предотвращайте внедрение данных в JSON/URL.
  • Обрабатывайте таймауты и отмену через context.
  • Ограничивайте повторные попытки и контролируйте backoff.

GDPR/Конфиденциальность: не логируйте PII (персональные данные) в открытом виде. Маскируйте чувствительные поля перед записью в логи.

Отладка и тестирование

Чек-лист для отладки:

  • Проверить URL и query-параметры (используйте net/url).
  • Убедиться, что Content-Type соответствует телу запроса.
  • Посмотреть raw-трафик через прокси (mitmproxy) или tcpdump при отладке.
  • Тестировать ответы с mock-серверами или тестовыми эндпоинтами, такими как reqres.in.

Критерии приёмки:

  • Запрос успешно отправляется без ошибок.
  • Ответ имеет ожидаемый HTTP-статус (200/201/204 и т.д.).
  • Тело ответа корректно декодируется в структуру (если предусмотрено).
  • Время отклика укладывается в требуемый SLO.

Быстрая шпаргалка (cheat sheet)

  • Создать request: req, err := http.NewRequest(“METHOD”, url, body)
  • Установить заголовок: req.Header.Set(“Content-Type”, “application/json”)
  • Запустить: client := &http.Client{Timeout: 10 * time.Second}; resp, err := client.Do(req)
  • Прочитать тело: body, err := io.ReadAll(resp.Body); defer resp.Body.Close()
  • Упростить GET: resp, err := http.Get(url)
  • Упростить POST JSON: resp, err := http.Post(url, “application/json”, bytes.NewBuffer(jsonBytes))

Сравнение HTTP-методов (краткая матрица)

МетодНазначениеТело запросаИдемпотентность
GETЧтениеНетДа
POSTСозданиеДаНет
PUTЗамена/обновлениеДаДа
PATCHЧастичное обновлениеДаЧастично
DELETEУдалениеОбычно нетДа

Примечание: идемпотентность — свойство безопасного повторного выполнения без изменения состояния несколько раз.

Ментальные модели и эвристики

  • “CRUD → HTTP”: связывайте бизнес-операцию (создать/читать/обновить/удалить) с соответствующим HTTP-методом.
  • “Тело только когда нужно”: не отправляйте тело в GET/DELETE по умолчанию; используйте query-параметры.
  • “Короткие таймауты в клиенте”: таймауты защищают от зависших сетевых вызовов.
  • “Опирайтесь на статус”: всегда проверяйте HTTP-статус перед декодированием тела.

Ролевые чек-листы

Разработчик:

  • Добавить обработку ошибок и таймауты.
  • Использовать context для отмены.
  • Покрыть функцию unit-тестами с моками.

QA-инженер:

  • Смоделировать неуспешные статусы (500, 429, 401).
  • Проверить поведение при обрыве соединения.
  • Валидировать обработку некорректного JSON.

Ops/DevOps:

  • Настроить мониторинг ошибок и латентности.
  • Ограничить скорость запросов к внешним API.
  • Настроить секреты/ключи через безопасный сторедж.

Decision flow: как выбрать метод (Mermaid)

flowchart TD
  A[Нужно ли изменить ресурс?] -->|Нет| B[GET]
  A -->|Да| C[Создать или обновить?]
  C -->|Создать| D[POST]
  C -->|Обновить| E[Полное обновление -> PUT]
  C -->|Частичное| F[PATCH]
  G[Удалить?] -->|Да| H[DELETE]
  style A fill:#f9f,stroke:#333,stroke-width:1px

Примеры ошибок и когда подход не сработает

  • Если API требует аутентификацию через нестандартные заголовки — используйте request.Header и добавьте токен.
  • Если требуется потоковая обработка (streaming), простое чтение io.ReadAll не подойдёт — используйте потоковое чтение и декодирование.
  • Для больших файлов используйте multipart/form-data и io.Pipe вместо загрузки всего в память.

Советы по производительности

  • Переиспользуйте http.Client для множества запросов (не создавайте новый клиент на каждый запрос).
  • Используйте Keep-Alive и контролируйте MaxIdleConns в transport, если много одновременных запросов.
  • При необходимости включите gzip-сжатие на стороне сервера и указывайте Accept-Encoding в заголовках.

Короткий глоссарий (одно предложение каждый термин)

  • HTTP: протокол для передачи гипертекста и запросов в сети.
  • REST API: архитектурный стиль для взаимодействия через HTTP.
  • idempotent: операция, повторённая несколько раз, даёт тот же результат.
  • JSON: формат обмена данными, часто используемый в REST API.

Итог и рекомендации

Net/http в Go — универсальный инструмент для работы с HTTP. Для небольших скриптов подойдёт http.Get/http.Post, для производственных приложений — http.NewRequest с настраиваемым http.Client, таймаутами и обработкой ошибок. Тестируйте через mock-серверы, логируйте аккуратно (без PII) и используйте HTTPS.

Summary:

  • Используйте http.NewRequest + http.Client для гибкости.
  • Всегда обрабатывайте ошибки и закрывайте response.Body.
  • Настраивайте таймауты и контекст для отмены.

Если хотите, могу добавить пример с аутентификацией Bearer Token, демо с context.WithTimeout или тесты с httptest.Server.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Macro Focus на Pixel 7 Pro — макро фото и видео
Фото

Macro Focus на Pixel 7 Pro — макро фото и видео

Как изменить циферблат Apple Watch и настроить компликации
Гаджеты

Как изменить циферблат Apple Watch и настроить компликации

Обновление драйверов NVIDIA — быстро и безопасно
Драйверы

Обновление драйверов NVIDIA — быстро и безопасно

Drummer в GarageBand — полный практический гид
Музыка

Drummer в GarageBand — полный практический гид

Копирование, перемещение и удаление файлов в PowerShell
PowerShell

Копирование, перемещение и удаление файлов в PowerShell

Настройка чувствительности тачпада в Windows 11
Windows

Настройка чувствительности тачпада в Windows 11