Ответ
Middleware (или "промежуточное ПО") в контексте веб-серверов на Go — это функция или компонент, который встраивается в цепочку обработки HTTP-запроса до того, как он достигнет основного обработчика (handler). Middleware позволяет выполнять сквозную логику для множества эндпоинтов.
По сути, это реализация паттерна Декоратор или Цепочка обязанностей.
Основные задачи, решаемые с помощью Middleware:
- Логирование (Logging): Запись информации о каждом входящем запросе.
- Аутентификация и авторизация: Проверка токенов, сессий, прав доступа.
- Восстановление после паник (Recovery): Перехват паник в обработчиках, чтобы сервер не падал.
- Сжатие (Compression): Сжатие ответов (например, с помощью gzip).
- CORS (Cross-Origin Resource Sharing): Добавление необходимых заголовков для кросс-доменных запросов.
- Добавление контекста: Обогащение
context.Context
запроса, например,request_id
.
Реализация с net/http
:
Идиоматичный способ реализации middleware в Go — это функция, которая принимает http.Handler
и возвращает новый http.Handler
.
package main
import (
"log"
"net/http"
"time"
)
// loggingMiddleware логирует время выполнения запроса.
func loggingMiddleware(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.RequestURI, time.Since(start))
})
}
// mainHandler - наш основной обработчик.
func mainHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
}
func main() {
// Создаём основной обработчик.
finalHandler := http.HandlerFunc(mainHandler)
// Оборачиваем его в наш middleware.
http.Handle("/", loggingMiddleware(finalHandler))
log.Println("Server is starting on :8080...")
http.ListenAndServe(":8080", nil)
}
Ключевые моменты:
- Компонуемость: Middleware легко объединяются в цепочки:
middleware1(middleware2(myHandler))
. - Стандартный интерфейс: Использование
http.Handler
делает middleware совместимым со стандартной библиотекой и большинством фреймворков (например, Chi, Gorilla Mux). - Популярные фреймворки (Gin, Echo) предоставляют свои, более удобные способы определения и подключения middleware, но базовый принцип остаётся тем же.