Веб на стандартной библиотеке Go
См. также: Фреймворки и библиотеки Go · Пример микросервиса · Gin · Важные интерфейсы.
Зачем stdlib, если есть Gin и Echo
Пакет net/http — полноценный HTTP-стек: сервер, клиент, TLS, cookies, multipart. Фреймворки строятся поверх него (кроме Fiber на fasthttp). Умение писать на stdlib нужно, чтобы:
- понимать, что делают middleware и контекст во фреймворках;
- собирать лёгкие сервисы без лишних зависимостей;
- встраивать сторонние
http.Handlerв существующий сервер.
Маршрутизация
Классический ServeMux
mux := http.NewServeMux()
mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
})
mux.HandleFunc("GET /users/{id}", userByID)
log.Fatal(http.ListenAndServe(":8080", mux))
С Go 1.22+ ServeMux понимает метод HTTP и шаблоны вроде {id} в пути. Параметры читают через r.PathValue("id").
Обработчик как http.Handler
type greetHandler struct{ prefix string }
func (h greetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s, %s", h.prefix, r.URL.Query().Get("name"))
}
mux.Handle("GET /hi", greetHandler{prefix: "Привет"})
Тип с методом ServeHTTP удобен, когда обработчик хранит зависимости (БД, конфиг).
Query, формы и multipart
| Источник | Как читать |
|---|---|
Query string ?a=1 | r.URL.Query().Get("a") |
application/x-www-form-urlencoded | r.ParseForm() → r.FormValue("email") |
multipart/form-data | r.ParseMultipartForm(maxMem) → r.FormValue, r.FormFile |
func contact(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
if err := r.ParseForm(); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
email := r.FormValue("email")
// ...
}
Для загрузки файлов — r.FormFile("avatar"), не забывать defer file.Close().
Middleware
Идиома — обёртка над http.Handler:
func withLogging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start))
})
}
mux.Handle("GET /api/", withLogging(apiHandler))
Цепочку можно собирать вручную или маленькой функцией chain(mw ...Middleware) http.Handler. Панику в production лучше перехватывать отдельным middleware и логировать, не полагаясь на «аварийный» ответ клиенту.
HTML-шаблоны
Пакет html/template (не text/template для веб-страниц) экранирует вывод и снижает риск XSS:
var page = template.Must(template.New("home").Parse(`
<!DOCTYPE html>
<html><body>
<h1>{{.Title}}</h1>
<p>Привет, {{.Name}}</p>
</body></html>
`))
func home(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
_ = page.Execute(w, struct {
Title, Name string
}{"Заметки", r.URL.Query().Get("name")})
}
Шаблоны компилируют один раз (template.Must при старте). Для JSON-API шаблоны не нужны — достаточно encoding/json (важные интерфейсы).
JSON-ответы
func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
_ = enc.Encode(v)
}
Ошибки API обычно оформляют единой структурой { "error": "..." } и фиксированными кодами HTTP.
Контекст запроса
r.Context() наследует отмену при обрыве клиента. Для таймаутов и отмены БД:
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
defer cancel()
row := db.QueryRowContext(ctx, "SELECT ...", id)
Подробнее о context.Context — в важных интерфейсах. Фреймворки прокидывают тот же контекст в свой API.
Корректная остановка сервера
ListenAndServe блокирует навсегда. Для деплоя в Kubernetes нужен graceful shutdown:
srv := &http.Server{Addr: ":8080", Handler: mux}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Printf("shutdown: %v", err)
}
Shutdown перестаёт принимать новые соединения и ждёт завершения активных запросов в пределах таймаута.
Когда переходить на фреймворк
| Задача | Stdlib достаточно |
|---|---|
| Healthcheck, webhook, внутренний API | Часто да |
| Группы маршрутов, валидация, OpenAPI | Удобнее Gin/Echo |
| Максимальный RPS на одном ядре | Смотреть бенчмарки; иногда Fiber |
Практика: Gin · Echo · Простые приложения.
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Основы языка Go - философия простоты, модель компиляции и идиоматичный подход к системной разработке. Go — это статически типизированный язык программирования общего назначения, разработанный компанией Google для создания эффективных, масштабируемых и надежных систем. Набор советов, правил, принципов и обычаев в разработке на этом языке. История Go - инженерные цели языка, философия простоты и эволюция инструментов экосистемы. Экосистема приложений на Go - встроенные инструменты, workflow разработки и практики сопровождения проектов. Кавычки, rune и string, точка, запятая, автоматическая вставка точки с запятой, скобки, подчёркивания и типичные ошибки новичков в Go. Предопределённые идентификаторы не являются ключевыми словами, но имеют специальное значение в языке. Их можно переопределить в локальной области видимости, но делать это не рекомендуется. Набор функций, которые включены в стандартную библиотеку языка. Особенности Go - интерфейсы, композиция, модель ошибок и практики написания поддерживаемого кода. Go вводит конкурентность через встроенные синтаксические конструкции и правила выполнения. Ниже рассматриваются основные направления практического применения Go, объяснённые через призму его технических характеристик и требований реальных инфраструктур. Типизация, набор правил определения типа данных значений языка.Основы языка Go
Что требуется знать перед началом изучения языка программирования Go
Рекомендации по разработке на Go
История языка Go
Экосистема приложений на Go
Синтаксис и пунктуация в Go
Ключевые слова языка Go
Встроенные функции и пакеты Go
Особенности языка Go
Синтаксические конструкции Go
Области применения Go
Типы данных и объявление переменных в Go