Перейти к основному содержимому

Код вокруг каждого обработчика

Middleware — это код, который выполняется вокруг ваших обработчиков: до того, как запрос дойдёт до них, после того, как ответ ушёл от них, или вместо них. Логирование, аутентификация, ограничение частоты запросов, сжатие — всё это middleware.

Одна и та же идея встречается под тремя именами: веб-фреймворки говорят middleware, gRPC говорит interceptor, некоторые экосистемы говорят filter. Одно понятие, три словаря.

В Go middleware — это функция, которая принимает обработчик и возвращает обёрнутый обработчик, то есть в точности паттерн Decorator из группы паттернов проектирования, а стек таких функций ведёт себя как Chain of Responsibility.


Middleware для логирования

withLog оборачивает любой обработчик: печатает входящий запрос, даёт обработчику выполнить работу и печатает снова на выходе. Сам обработчик при этом ничего об этом не знает.

Обернуть один раз, логировать всё

Обёрнутый обработчик обслуживает два разных пути, и оба попадают в лог — логирование написано один раз, в обёртке, а не в каждом обработчике.

Prompt
Напишите программу на Go с middleware withLog, которая оборачивает http.Handler, печатает строку со стрелкой, методом и путём перед вызовом следующего обработчика и строку «готово» после него. Оберните mux с двумя маршрутами, запустите сервер через httptest, выполните запросы к обоим путям и напечатайте ответы.
Вывод: программа на Go и захваченный вывод
Wrap once, log everything

Middleware, которое останавливает запрос

Middleware может также отказать: проверка аутентификации, не нашедшая корректного ключа, записывает 401 Unauthorized и никогда не вызывает следующий обработчик.

В цепочке withLog(withAuth(handler)) запрос проходит через слои по порядку, а ответ возвращается наружу через них же.

Слой аутентификации в цепочке

Запрос без ключа останавливается слоем аутентификации с кодом 401 — обработчик так и не выполняется. С ключом запрос проходит всю цепочку и добирается до данных.

Prompt
Напишите программу на Go с двумя связанными в цепочку middleware: withLog, которая печатает запрос, и withAuth, которая проверяет заголовок X-API-Key и отвечает 401, не вызывая следующий обработчик, если ключ неверный. Оберните обработчик данных как withLog(withAuth(handler)), запустите сервер через httptest, затем отправьте один запрос без ключа и один с ключом, напечатав оба статуса и оба тела ответа.
Вывод: программа на Go и захваченный вывод