HTTP-сервер, JSON API и итоговый проект

HTTP-сервер на net/http: регистрация обработчиков и формирование ответа

Содержание курса

http.ListenAndServe: блокирующий запуск, обработка ошибки и рабочий цикл с двумя терминалами

Когда маршрутизатор готов, его нужно передать серверу:

if err := http.ListenAndServe(":8080", mux); err != nil {
    log.Fatal(err)
}

http.ListenAndServe принимает адрес для прослушивания и http.Handler — интерфейс, который реализует *http.ServeMux. Функция открывает TCP-сокет на порту 8080 и входит в бесконечный цикл приёма соединений. Она блокирует текущую горутину — то есть строки после неё в нормальном режиме работы никогда не выполнятся.

Именно поэтому нельзя просто написать http.ListenAndServe(...) и продолжать код ниже: сервер занял поток и ждёт запросов.

Что происходит на практике:

  • Запускаете программу в первом терминале — он «зависает» (это нормально, сервер работает).
  • Открываете второй терминал и отправляете запрос:
# Linux / macOS
curl http://localhost:8080/hello

# Windows PowerShell
Invoke-WebRequest http://localhost:8080/hello
  • Сервер обрабатывает запрос, первый терминал может показать логи, второй — ответ.
  • Чтобы остановить сервер, нажимаете Ctrl+C в первом терминале.

Почему log.Fatal? ListenAndServe возвращает ошибку только в одном случае: что-то пошло не так при запуске или во время работы — например, порт уже занят другим процессом. Игнорировать эту ошибку нельзя: без неё вы не узнаете, что сервер вообще не стартовал. log.Fatal выводит сообщение и завершает программу с ненулевым кодом.

Типичная ошибка при занятом порте выглядит так:

2024/01/15 10:23:45 listen tcp :8080: bind: address already in use

Если написать http.ListenAndServe(":8080", mux) без проверки — программа завершится молча или продолжит выполнение с незапущенным сервером, и отлаживать это будет неудобно.