Как сделать HTTP-сервер на Go
В Go HTTP-сервер есть в стандартной библиотеке — пакет net/http. Ставить ничего не нужно:
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"time"
)
func main() {
http.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Главная страница")
})
http.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Привет, %s!\n", r.PathValue("name"))
})
http.HandleFunc("GET /api/time", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"time": time.Now().Format(time.RFC3339)})
})
log.Println("сервер запущен: http://localhost:8080")
log.Fatal(http.ListenAndServe("localhost:8080", nil))
}Сохраните как main.go в папке модуля и запустите go run .. Сервер работает, пока его не остановить сочетанием Ctrl+C. Проверьте в браузере http://localhost:8080/hello/anna или из второго окна терминала программой curl (она отправляет запрос и печатает ответ):
$ curl http://localhost:8080/hello/anna
Привет, anna!В Windows PowerShell слово curl может означать другую команду (Invoke-WebRequest) — набирайте curl.exe.
Как это устроено
http.HandleFunc(шаблон, функция)— какой функцией отвечать на какие адреса.- Функция-обработчик получает
w— куда писать ответ — иr— сам запрос: адрес, заголовки, параметры, тело.fmt.Fprintln(w, …)пишет текст в ответ так же, какPrintlnпишет на экран. http.ListenAndServe(адрес, nil)запускает сервер и не возвращается, пока он работает. Если запустить не удалось, функция вернёт ошибку, иlog.Fatalнапечатает её и завершит программу.
Шаблоны адресов (Go 1.22 и новее)
"GET /hello/{name}"— только метод GET;{name}— часть пути, её значение даётr.PathValue("name")."POST /items"— только POST. На запрос другим методом сервер сам ответит405 Method Not Allowed.- Шаблон, который кончается на
/, подходит ко всем адресам, начинающимся так же:"/static/". Поэтому шаблон"/"ловит вообще все адреса. Чтобы ответить только на главную, пишут"/{$}", как в примере. - Если подходят несколько шаблонов, выбирается более точный.
Методы и {параметры} в шаблонах появились в Go 1.22. Они работают, если в go.mod указана версия go 1.22 или новее. В примерах для старых версий метод проверяют вручную: if r.Method != http.MethodGet { … }.
Ошибки и коды ответа
Код ответа задают до того, как писать тело. Для ошибок есть готовая функция:
http.Error(w, "товар не найден", http.StatusNotFound)Она отправит код 404 и текст. Без явного кода сервер отвечает 200 OK.
Адрес: свой компьютер или вся сеть
"localhost:8080" — сервер доступен только с этого же компьютера. Так безопасно для разработки.
Адрес ":8080" (без имени) открывает сервер для всех сетей компьютера: его увидят другие устройства в локальной сети, а на сервере с внешним адресом — весь интернет. Открывайте порт наружу, только когда это действительно нужно, и не выставляйте в сеть отладочные адреса без пароля.
На сервере Linux порт закрывают и открывают брандмауэром (фильтром сетевых подключений) — для Ubuntu это справка Как открыть порт в Ubuntu.
Если не запускается
listen tcp 127.0.0.1:8080: bind: address already in use— порт занят другой программой или прошлым запуском того же сервера. Остановите её или выберите другой порт:"localhost:8081".- Порт ниже 1024 (
:80) в Linux требует прав root — для разработки берите 8080 и выше. 404 page not found— ни один шаблон не подошёл. Проверьте путь и метод запроса.
Для настоящего сервера
http.ListenAndServe не ограничивает время ожидания клиента. Для сервера, открытого в интернет, создают http.Server с таймаутами (пределами времени ожидания), например ReadHeaderTimeout: 5 * time.Second, и вызывают у него ListenAndServe(). Подробности — в документации пакета net/http.