Найти в Дзене
Я, Golang-инженер

#77. Middlware в Golang. Основы механик HTTP: стандартная библиотека Go и Echo

Это статья об основах программирования на Go. На канале я рассказываю об опыте перехода в IT с нуля, структурирую информацию и делюсь мнением. Хой, джедаи и амазонки! Продолжаю осваивать профессию программиста. Встретился в коде middlware, слышал о нём ранее и теперь решил разобраться лучше: что это и какую пользу несёт в приложении. В ходе изучения погрузился в понимание, как работают соответствующие механики в Go для работы с протоколом HTTP. Go разбираться! Middlware можно перевести как промежуточное ПО, связывающее две части сервиса. Это широкая трактовка, и контекстов применения middlware в таком виде нашёл четыре: В контексте веб-разработки, middlware - это часть приложения, которая разделяет процесс обработки запроса клиента на условные этапы. Далее я буду говорить о middlware только в этом контексте - как часть веб-приложения внутри основного сервиса. Вероятно это и есть основной и устоявшийся в IT-среде термин middlware - в контексте обработки веб-запросов. В middlware про
Оглавление

Это статья об основах программирования на Go. На канале я рассказываю об опыте перехода в IT с нуля, структурирую информацию и делюсь мнением.

Хой, джедаи и амазонки!

Продолжаю осваивать профессию программиста. Встретился в коде middlware, слышал о нём ранее и теперь решил разобраться лучше: что это и какую пользу несёт в приложении.

В ходе изучения погрузился в понимание, как работают соответствующие механики в Go для работы с протоколом HTTP.

Go разбираться!

1. Основы middlware

1.1. Общие данные

Middlware можно перевести как промежуточное ПО, связывающее две части сервиса. Это широкая трактовка, и контекстов применения middlware в таком виде нашёл четыре:

  • Ряд специалистов считают за middlware всё ПО, что выше транспортного уровня и ниже уровня приложения модели OSI (см. публикацию о сетевой модели OSI: *клик);
  • Всё ПО между ОС и пользователем - например, bash оболочка или GUI;
  • Промежуточный сервер между клиентом и сервером, например для связи нового клиентского приложения с устаревшим сервером и постепенное написание нового сервера с тенденцией полного перехода клиентских запросов на него;
  • Службы доступа к БД;
  • Часть кода веб-приложения до или после основной обработки запроса.

В контексте веб-разработки, middlware - это часть приложения, которая разделяет процесс обработки запроса клиента на условные этапы. Далее я буду говорить о middlware только в этом контексте - как часть веб-приложения внутри основного сервиса. Вероятно это и есть основной и устоявшийся в IT-среде термин middlware - в контексте обработки веб-запросов.

В middlware происходит предварительная обработка, а далее - основная обработка запроса. Практика показывает, что это более жизнеспособная история, чем писать весь код в один обработчик.

В веб-разработке middlware - это просто часть кода, которая позволяет перед и/или после основной обработки запроса, сделать с запросом определённые манипуляции, удобные для поддержки кода в сложных проектах. Это просто код, ничего особенного; в стандартной библиотеке Go есть специальные функции для удобства работы с таким подходом через middlware.

Middleware позволяет добавлять функциональность к обработчику запроса, не изменяя его исходный код.

Типичные сценарии использования middlware:

  • Авторизация/аутентификация;
  • Кеширование данных для быстрого ответа на повторяющиеся одинаковые запросы (та же приветственная страница для незагеристрированного пользователя);
  • Логирование;
  • Валидация данных из запроса и т.д.

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

Рассмотрим пример с middlware без разбора кода, затем немного посмотрим на механики http, и затем уже начнём разбирать middlware. В конце разберём, как работать с http и middlware во фреймворке Echo.

1.2. Простой middlware

Напишем сервер с двумя обработчиками: первый возвращает слово pong, а второй возвращает фразу "Golang-инженер". Суть в том, что обработчиков может быть много и с разным функционалом, но для всех для них может быть один middlware, который выполняет некую полезную работу, что сокращает код. Здесь middlware логирует начало и завершение выполнения запроса:

Код
Код

Пример вывода в терминал при обращении через браузер к двум эндпоинтам:

Работа в терминале
Работа в терминале

С выводом в терминал всё должно быть понятно. Скрины с браузера не показываю, думаю тоже всё понятно. А с регистрацией обработчика с миддлвеар всё не так однозначно.

2. Разбираемся со штатным middlware в Go

2.1. Вводные данные

Сравним регистрацию обработчика с миддлвеар с обычной регистрацией обработчика из примера выше:

http.Handle("/ping", loggingMiddleware(http.HandlerFunc(pingHandler)))
vs
http.HandleFunc("/ping", pingHandler)

Оба варианта регистрируют функцию-обработчик для эндпоинта /ping. Общее у двух вариантов это эндпоинт и функция-обработчик pingHandler. Далее пошли различия, начнём с http.HandlerFunc.

2.2. HandlerFunc - тип для функции-обработчика http

http.HandlerFunc - это тип данных, к которому должна быть приведена функция, чтобы она могла обрабатывать http-запросы. Этот тип данных ещё называют адаптером. Вот как он представлен в библиотеке http:

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Может возникнуть вопрос: зачем нужен этот адаптер, если в функции HandleFunc нет никаких адаптеров, и pingHandler используется напрямую.

Дело в том, что функция HandleFunc скажем так, узкоспециализированная, а Handle - наоборот, более универсальная. И внутри HandleFunc всё равно происходит оборачивание функции pingHandler в тип HandlerFunc.

Вопрос: Зачем нам нужно оборачивать функцию в именованный тип функции?

Ответ: Этот тип HandleFunc используется в методе в ServeHTTP:

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Вот метод ServeHTTP уже описан в важном интерфейсе Handler.

2.3. Интерфейс Handler

2.3.1. Общие сведения

Вот какое описание у интерфейса Handler:

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Интерфейс Handler используется для обработки запросов клиентов по протоколу HTTP.

Этот интерфейс требует метода ServeHTTP с вполне конкретной сигнатурой. По сути, этот интерфейс позволяет использовать функции и структуры в качестве обработчиков. Для функции требование - чтобы у неё была сигнатура (ResponseWriter, *Request), а для структуры - чтобы у неё был конкретно метод с таким названием и такой сигнатурой, как прописано в интерфейсе.

В стандартной библиотеки Go есть разные реализации ServeHTTP, вызываемые "под капотом" в зависимости от логики. Посмотрим на все стандартные методы ServeHTTP, описанные для Go 1.23.5. Всего их семь. Вчитываться необязательно, просто для понимания что есть несколько базовых ServeHTTP-методов в Go.

2.3.2. Пример 1/7 ServeHTTP

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Базовая реализация для непосредственного вызова функции-обработчика.

2.3.3. Пример 2/7 ServeHTTP

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Используется "под капотом", когда обработчик перенаправляет запрос на другой URL, например:

http.RedirectHandler("https://example.com", http.StatusMovedPermanently)

2.3.4. Пример 3/7 ServeHTTP

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Используется "под капотом", когда создан персональный мультиплексор, например:

mux := http.NewServeMux()
mux.HandleFunc("/ping", pingHandler)

Определяет необходимый обработчик, соответствующий URL запрошенного ресурса.

2.3.5. Пример 4/7 ServeHTTP

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Используется "под капотом" в первую очередь, когда на порт, на котором запущен программный сервер, поступил HTTP-запрос. Можно сказать, что это главный обработчик HTTP-запросов в Go.

2.3.6. Пример 5/7 ServeHTTP

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Привёл фрагмент метода, т.к. с трок много.

Этот обработчик используется для ограничении времени выполнения запроса, например:

http.Handle("/timeout", http.TimeoutHandler(http.HandlerFunc(pingHandler), 1*time.Second, "таймаут"))

Функция TimeoutHandler - это конструктор, который создаёт экземпляр структуры, см. ниже:

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Конечно же, этот экземпляр структуры соответствует интерфейсу Handler.

В каком-то смысле, TimeoutHandler - это middlware, добавляющий функционал таймаута к исходному обработчику.

2.3.7. Пример 6/7 ServeHTTP

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Я не разобрался, в каких случаях запускается эта функция. Судя по комментарию структуры, метод HTTP-запроса должен быть OPTIONS, а эндпоинтом будет *?

Если понимаете, как это работает - напишите.

Также по идее этот метод рассчитан, что в теле запроса не более определённого количества бит информации. Если больше - то соединение закрывается, т.к. считается атакой на сервер.

Почитать о белом хакинге можно здесь.

4 << 10 означает 4, сдвинутые влево на 10 битов:

4 << 10 = 4 х 2^10 = 4 х 1024 = 4096 бит = 4 кибибайта.

2.3.7. Пример 7/7 ServeHTTP

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Как я понимаю, используется для соединения типа HTTPS, т.е. с шифрованием.

На этом всё со стандартными методами ServerHTTP.

Итак, мы разобрали эту часть кода:

http.Handle("/ping", loggingMiddleware(http.HandlerFunc(pingHandler)))

Идём дальше - смотрим функцию loggingMiddlware.

2.4. Middlware

Функцию-миддлвеар мы пишем сами, это не стандартная функция в Go:

Пример миддлвеар-функции
Пример миддлвеар-функции

Middlware принимает данные типа интерфейс http.Handler и возвращает новые данные такого же типа; при этом встраивает дополнительную логику до и/или после логики обработчика.

Итак, мы обернули функцию pingHandler в тип HandlerFunc. Благодаря этому наша функция pingHandler начала соответствовать интерфейсу Handler.

Если в функцию Handle /http.Handle("/ping", loggingMiddleware(http.HandlerFunc(pingHandler)))/ передать вторым аргументом функцию, которая принимает интерфейсный тип данных Handler и возвращает такой же интерфейсный тип данных Handler, то мы получили миддлвеар.

Что здесь в коде middlware необычного. А из необычного здесь только метод ServeHTTP.

При исполнении строки ServeHTTP управление передаётся в тот обработчик, который вложен внутри middlware.

Остаётся вопрос, почему взят именно такой метод. Вспомним, что у параметра next нашей функции-middlware интерфейсный тип, и в нём единственный метод ServeHTTP. Простейшая его реализация выглядит так:

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

ServeHTTP - это стандартная функция, для которой нужен приёмник (ресивер) с типом HandlerFunc. А это и есть наша функция pingHandler, обёрнутая в соответствующий тип.

Вот вроде бы и всё. С виду непонятная конструкция middlware складывается в понятную картинку. Осталось разобрать ещё главную функцию - Handle, чтобы всё стало ещё понятнее.

2.5. Handle

2.5.1. Общие сведения

http.Handle - это функция для привязки эндпоинта к обработчику. Считается более универсальной, чем http.HandleFunc, т.к. может работать со структурами помимо функций-обработчиков.

Эта функция принимает два аргумента: эндпоинт ("/ping") и тип http.Handler.

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Глобальная переменная use121 как я понимаю, связана с тем, использовать ли способ мультиплексирования версии Go 1.21, или использовать более новую версию. У меня установлен Go 1.23, в других версиях Go может быть здесь какая-то другая переменная.

Значение этой булевой переменной use121 считывается из переменной окружения. Если переменная окружения не установлена, то будет использована новая реализация мультиплексирования для протокола HTTP/1.1.

Т.е. в моём случае используется функция register. Далее в глубину разбирать не буду.

2.5.2. Handle/HandleFunc с мультиплексором по-умолчанию

Посмотрим на реализацию функции HandleFunc для сравнения с Handle:

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Как видите, Handle отличается от HandleFunc при новом использовании мультиплексирования только тем, что в HandleFunc происходит оборачивание аргумента в тип HandlerFunc. А дальнейшая логика у Handle и HandleFunc одинаковая.

2.5.2. Handle/HandleFunc с кастомным мультиплексором

Если мы использовали мультиплексор не по-умолчанию, а сделали свой:

Код
Код

То функция Handle или HandleFunc будут выглядеть следующим образом:

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Т.е. функция превращается в метод с приёмником - нашим кастомным мультиплексором, точнее - указателем на него.

В принципе то же самое, только метод resister вызывается для другого экземпляра структуры.

На этом базовый разбор middlware закончен. Прежде чем переходить к библиотеке echo, хочу рассмотреть ещё три интересных момента:

  1. Передача функции по-значению в качестве аргумента;
  2. Структура как обработчик;
  3. Миддлвеар обёрнутый в миддлвеар.

2.6. Передача функции по-значению в качестве аргумента

2.6.1. Общие сведения

Я часто видел код в целях например экономии памяти, когда минуя создание промежуточной переменной пишется что-то вроде такого:

amount, err := calculate(amountNew, findExponent(currency))

или такого:

return calculate(amountNew, findExponent(currency))

Здесь всё понятно, мы в качестве второго аргумента передаём в функцию calculate результат выполнения другой функции - findExponent.

Но при регистрации эндпоинта мы используем в качестве аргумента функцию без её вызова:

http.HandleFunc("/ping", pingHandler)

или если с middlware:

mux.Handle("/ping", loggingMiddleware(http.HandlerFunc(pingHandler)))

Что это за странный синтаксис и как его использовать где-то помимо регистрации маршрутов? Мы не заглядывали вглубь метода register (см. предыдущий параграф), чтобы понять как происходит работа с таким типом аргумента. Напишем простой пример и посмотрим как это выглядит.

2.6.2. Пример передачи функции по-значению

Рассмотрим код:

Код
Код

Здесь в функцию ApplyFunc первым аргументом передаётся функция double по-значению без её вызова.

Можно рассматривать функцию передачи по-значению как некий шаблон, с которым работает другая функция и сама решает какой аргумент в него передать. Например, с учётом некоторых условий.

Также при регистрации обработчика:

http.HandleFunc("/ping", pingHandler)

В HandleFunc мы передаём шаблон - функцию pingHandler. А в функции HandleFunc будет принято решение, какие аргументы передать в этот pingHandler.

Примерно та же схема будет при передачи метода в качестве аргумента:

Код
Код

Такой подход - важная штука для принципа O в SOLID - открытости/закрытости. Когда мы можем передавать в функцию некие шаблоны исполнения, и просто изменяя эти шаблоны можем получить новый функционал.

Подробнее о SOLID и чистом коде / чистой архитектуре можно посмотреть в ультимативном разборе чистого кода на YouTube без привязки к конкретному языку.

Теперь посмотрим на структуру в качестве обработчика.

2.7. Структура как обработчик в Go

2.7.1. Общие сведения

Как мы помним, за обработку запросов по протоколу HTTP отвечает интерфейс Handler пакета http. Любой тип, реализующий интерфейс http.Handler, может обрабатывать HTTP-запросы. Напомню, как выглядит интерфейс:

Фрагмент стандартной библиотеки Go
Фрагмент стандартной библиотеки Go

Есть несколько стандартных реализаций метода ServeHTTP в Go в зависимости от структуры, и эти методы предназначены для реализации обработки в зависимости от логики: от первичного приёма http-запроса до вызова непосредственной функции-обработчика.

Мы можем сделать свою собственную структуру и метод ServeHTTP для этой структуры, чтобы использовать их в комплексе как обработчик.

2.7.2. Структура-обработчик

Рассмотрим код, когда мы хотим хранить в обработчике какую-то информацию, например количество запросов, обращённых к нему на сервере.

Код
Код

Запустим сервер и сделаем запрос в браузере пять раз. Каждый раз получаем данные из структуры:

Браузер
Браузер

Как видим, благодаря структуре-обработчику, мы получили дополнительный функционал. Корректнее будет сказать, что обработчик всё-таки не структура, а структура и её метод.

Для каких ещё целей в реальных приложениях можно применять такой подход со структурой-обработчиком? Возможно с какими-то ограничениями, например, обрабатывать определённое количество одновременно выполняемых запросов. Трудно ещё что-то сказать имея текущую насмотренность. Пока примем к сведению, что такое просто возможно и будем знать, как это выглядит, если встретим в чужом коде.

2.8. Middlware обёрнутый в middlware

Можно один middlware обернуть в другой middlware. Например, если у нас есть череда пре/пост обработки запроса клиента, слабосвязанные друг с другом, чтобы помещать их в один middlware.

Пока что мы добавили за счёт middlware логирование. Что ещё можно добавить в middlware помимо логов? Добавим, например, валидацию размета тела запроса: если будет слишком большое тело, то не обрабатываем запрос:

Код
Код

В строке регистрации обработчиков добавил ещё один middlware: validationRequest. В этом методе делаю проверку и если запрос не проходит проверку, то обработка завершается без вызова следующего обработчика: логгера и, соответственно, pingHandler'а.

Вот что покажет Postmen, в тело запроса которого я просто скопировал текст который уже написал в этой публикации:

Postman
Postman

А вот логи из терминала:

Терминал
Терминал

Научились оборачивать middlware в middlware.

2.9. Цепочка из middlware

Middlware может быть много: целая цепочка вызовов до и/или после обработки основного запроса, а не только два штуки. Представьте, как может увеличиться эта строка если у нас хотя бы пять middlware:

http.Handle("GET /ping", validationRequest(loggingMiddleware(http.HandlerFunc(pingHandler))))

Один из вариантов упростить понимание кода со множеством middlware - поэтапное оборачивание middlware в middlware:

Код
Код

Ещё можно придумать вариант - использовать срез и итерацию по этому срезу. Но это на мой взгляд уже нагороженный вариант.

Итак, это всё что хотел рассмотреть по middlware, создаваемому штатными средствами Go. Есть ещё один интересный момент, который особо не связан с middlware, но я с ним познакомился пока его изучал.

2.10. Главное о middlware

Middlware - это обычная функция, которая принимает тип данный, пригодный для обработки http-запросов и возвращает такой же тип данных. В стандартной библиотеке net/http такой тип данных - интерфейс http.Handler.

Внутри middlware происходит работа с запросом без задействования основного функционала главного обработчика. Когда понадобится главный (следующий в цепочке) обработчик, он вызывается как метод.

Middlwaree ближе всего к принципу O - Open/Closed - принципу открытости/закрытости SOLID (второй раз встречается этот принцип в этой публикации; первый - при передаче функции по-значению в другую функцию). Т.к. мы не хотим изменять логику существующего кода, в т.ч. чтобы не получить неожиданное поведение и необходимость новых тестов; мы хотим дописать что-то новое, не влияющее на ранее написанную логику, и получить новое поведение.

Посмотрим, как это работает в библиотеке echo.

3. Middlware в библиотеке Echo

3.1. Введение

Echo - это библиотека с улучшенным функционалом для обработки http-запросов в сравнении со стандартной библиотекой net/http. Это одна из многих других нестандартных библиотек для работы с http-запросами.

Постепенно стандартная библиотека Go обновляет функционал, и необходимость в сторонних библиотеках по работе с http падает. Например, с версии Go 1.22 появилась возможность прописывать метод при регистрации обработчика:

Код:

Код
Код

Ответ в Postman при POST-запросе:

Postman
Postman

Т.е. мы уже не пишем примерно так:

if r.Method != http.MethodGET{...}

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

Возвращаемся к Echo. На GitHub есть пример в ReadMe, причём с middlware:

-31

По-наитию можно сразу сориентироваться, что делает этот код:

  1. Создаёт экземпляр сервера Эхо e := echo.New();
  2. Добавляет штатные middlware, по сути у нас получилась цепочка из двух middlware;
  3. Регистрирует эндпоинт /, связывая его с обработчиком hello.

У нас есть целая пачка предустановленных middlware в библиотеке Echo, почитать можно в официальной документации:

Официальная документация Echo в части Middlware
Официальная документация Echo в части Middlware

Сразу бросается в глаза Body Limit который судя по названию как раз осуществляет валидацию по объёму тела запроса. А также middlware JWT судя по названию связан с аутентификацией по JWT-токену.

На данный момент этих стандартных middlware 25 штук.

Если запустить код, представленный выше, и обратиться к серверу, то получим в терминале:

Терминал
Терминал

В браузере:

Браузер
Браузер

В терминале логи, выводятся через middlware Logger, предустановленном в Echo. Он выводит информацию в виде yaml-данных, более читабельный вариант этих логов через форматирование см. ниже:

Работа в https://syshunt.com/yaml-formatter/
Работа в https://syshunt.com/yaml-formatter/

Напишем код из параграфа 2, используя инструментарий Echo.

3.2. Пишем Middlware в Echo

Напишем сразу итоговый вариант из предыдущей главы с двумя middlware: логгер оставлю кастомным, валидацию по размеру тела запросу возьму предоставляемый Echo.

Код
Код

Здесь понадобилось доработать весь код: логика прежняя, детали реализации изменились. Например, мы уже работаем в middlware не с типом http.Handler, а с типом echo.HandlerFunc.

Запустим сервер и отправим запрос с большим телом запроса:

Postman
Postman

Видим примерно тот же результат, что был с кастомным middlware, только ещё пришло сообщение в теле запроса.

Отдельно стоит сказать про аргумент, передаваемый в стандартный для Echo middlware BodyLimit:

e.Use(middleware.BodyLimit("1K"))

В примере аргумент представлен как , но можно указывать и цифрами, например 1000. По сути буквы - это сокращения от наименования данных, а цифры - сколько этих данных; вот какие допускаются буквы:

B - байт (сейчас 8 бит, ранее иначе могло быть);

K - кибибайт (1024 байт);

M - мебибайт (1024 кибибайт);

G - гибибайт (1024 мебибайт);

T - тебибайт (1024 гибибайт);

P - пебибайт (1024 тебитайт).

А это фрагмент из доки Echo к этому middlware:

https://echo.labstack.com/docs/middleware/body-limit#usage
https://echo.labstack.com/docs/middleware/body-limit#usage

Тело http-запроса с петабайтом данных, это конечно сильно. Но что есть, то есть. Кстати, в доке указан ещё икс, т.е. "x". Смысла в нём нет, как собственно и в буквах. И если 4xB равнозначно 4B, то по-моему проще писать ограничение просто 4 или 4000 или какое нужно там ограничение.

Возможно такая передача данных предназначена для супер-оптимизации: например дешевле передать строку K, чем строку 1000.

В общем, вот так выглядит middlware в Эхо. Цепочки middlware удобно делать из построчных методов типа e.Use(...), представленных выше. Хотя можно и прям в метод регистрации эндпоинта прописывать через запятую, вот сигнатура:

Код
Код

Отдельно хочу показать, как применить middlware в Echo для определённых маршрутов.

3.3. Middlware к определённому маршруту

Можем создать группу, начинающуюся с определённого маршрута, к которым будет применяться middlware из этой группы:

Код
Код

В браузере запрос уже должен быть /api/ping:

Браузер
Браузер

Тут несложно сориентироваться, как настроить разные группы или обрабатывать запросы без групп middlware.

В целом, на этом этапе можно считать что с middlware разобрались на приличном уровне для уверенного их использования стандартной библиотекой и через библиотеку Echo.

4. Выводы

Ниже перечислены те вещи, с которыми познакомились в публикации:

  1. Отличие функций Handle и HandleFunc пакета http: Handle - более универсальная;
  2. Познакомились с типом данных http.HandlerFunc, как в него происходит оборачивание обычной функции при использовании HandleFunc и Handle;
  3. С интерфейсом http.Handler, сигнатурой метода этого интерфейса http.ServeHTTP, семью вариантами этого метода в стандартной библиотеке Go и кастомным ServeHTTP для использования структур в качестве обработчиков;
  4. Передачей функций и методов по-значению в качестве аргумента функции;
  5. Научились писать Middlware в стандартной библиотеке Go и составлять цепочки middlware для удобства чтения кода;
  6. Научились валидировать запрос по размеру тела запроса и отклонять, если запрос слишком велик;
  7. Узнали, что в Go начиная с версии 1.22 улучшился стандартный пакет http, в частности - появилась возможность добавлять метод при регистрации маршрута.
  8. Познакомились с библиотекой Echo и для чего она нужна;
  9. Научились писать middlware в Echo;
  10. Научились составлять цепочки middlware в Echo;
  11. Научились регистрировать группу маршрутов в Echo, для выбора определённых цепочек middlware;
  12. Узнали, что есть предустановленные middlware в Echo: 25 вариантов от авторизации до таймаутов.

Ниже собрал ссылки на ресурсы из публикации:

Познакомился я с middlware, изучая репозиторий компании, в которой прохожу стажировку. Вакансию на эту стажировку нашёл через акселерацию Яндекс Практикума, которая идёт как бонусный и необязательный курс для тех, кто прошёл их основной курс. Если вдруг захотите узнать подробнее о Практикуме или акселерации, можете написать мне в ТГ. Также у меня есть скидка для покупки курсов этой компании.

Если понравилась эта публикация, могут быть интересны эти:

  • Безопасное завершение приложения через Graceful Shutdown: "клик";
  • KISS & DRY в Go: "клик";
  • Разбираемся с Docker: "клик".

Благодарю, что дочитали публикацию до конца. Верьте в себя и свои силы, развивайтесь нравственно, физически и интеллектуально, и у вас всё получится. Успехов! И будем на связи.

https://ru.freepik.com/free-photo/lavender-field-village-france_10480059.htm
https://ru.freepik.com/free-photo/lavender-field-village-france_10480059.htm

Бро, ты уже здесь? 👉 Подпишись на канал для начинающих IT-специалистов «Войти в IT» в Telegram, будем изучать IT вместе 👨‍💻👩‍💻👨‍💻