1 added
1 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>При разработке веб-приложений разработчики сталкиваются с задачами, которые нужно решать на каждом этапе обработки запроса. Например, если у нас есть несколько маршрутов, которые требуют аутентификации, или если нам нужно логировать все входящие запросы, то реализация этой логики в каждом маршруте может привести к дублированию кода и усложнению поддержки приложения. Это также увеличивает вероятность ошибок, так как любой измененный маршрут необходимо будет обновить в нескольких местах. Использование мидлвар позволяет решить эти проблемы.</p>
1
<p>При разработке веб-приложений разработчики сталкиваются с задачами, которые нужно решать на каждом этапе обработки запроса. Например, если у нас есть несколько маршрутов, которые требуют аутентификации, или если нам нужно логировать все входящие запросы, то реализация этой логики в каждом маршруте может привести к дублированию кода и усложнению поддержки приложения. Это также увеличивает вероятность ошибок, так как любой измененный маршрут необходимо будет обновить в нескольких местах. Использование мидлвар позволяет решить эти проблемы.</p>
2
<p>Мидлвара - это функции, которые обрабатывают запросы и ответы в веб-приложениях. Они выполняются между получением запроса от клиента и отправкой ответа. Они могут выполнять различные задачи, такие как проверка прав доступа, логирование или преобразование данных в ответе</p>
2
<p>Мидлвара - это функции, которые обрабатывают запросы и ответы в веб-приложениях. Они выполняются между получением запроса от клиента и отправкой ответа. Они могут выполнять различные задачи, такие как проверка прав доступа, логирование или преобразование данных в ответе</p>
3
-
<p>В этом уроке мы р��ссмотрим, как создавать и использовать мидлвары в Slim, а также изучим примеры их применения</p>
3
+
<p>В этом уроке мы рассмотрим, как создавать и использовать мидлвары в Slim, а также изучим примеры их применения</p>
4
<h2>Оборачивание</h2>
4
<h2>Оборачивание</h2>
5
<p>Прежде чем перейти к изучению непосредственно мидлвар, разберем их принцип действия на примере обычных функций.</p>
5
<p>Прежде чем перейти к изучению непосредственно мидлвар, разберем их принцип действия на примере обычных функций.</p>
6
<p>Представим, что у нас есть функция, которая прибавляет 5 к аргументу:</p>
6
<p>Представим, что у нас есть функция, которая прибавляет 5 к аргументу:</p>
7
<p>Наша задача расширить поведение этой функции, при этом не меняя саму функцию. Например, мы хотим прибавлять 5 к удвоенному значению аргумента. Чтобы решить эту задачу, мы можем написать новую функцию, которая будет внутри себя использовать уже существующую:</p>
7
<p>Наша задача расширить поведение этой функции, при этом не меняя саму функцию. Например, мы хотим прибавлять 5 к удвоенному значению аргумента. Чтобы решить эту задачу, мы можем написать новую функцию, которая будет внутри себя использовать уже существующую:</p>
8
<p>Точно так же мы можем расширить и вторую функцию:</p>
8
<p>Точно так же мы можем расширить и вторую функцию:</p>
9
<p>В общем случае расширение функции выглядит так:</p>
9
<p>В общем случае расширение функции выглядит так:</p>
10
<p>Чтобы расширить поведение функции, нужно создать новую функцию, которая будет использовать исходную. Главное условие - интерфейсы обоих методов должны совпадать: количество и тип аргументов, а также тип возвращаемого результата должны быть одинаковыми. Тогда вы можете просто заменить в коде вызов одной функции на вызов другой, обернутой, и код продолжит работать без изменений, поскольку интерфейс остался прежним. В этом случае код, использующий вашу новую функцию, не заметит, что она обернута и его не потребуется переписывать. Этот подход также называется декорированием и описывается в справочниках по шаблонам проектирования как "паттерн Декоратор".</p>
10
<p>Чтобы расширить поведение функции, нужно создать новую функцию, которая будет использовать исходную. Главное условие - интерфейсы обоих методов должны совпадать: количество и тип аргументов, а также тип возвращаемого результата должны быть одинаковыми. Тогда вы можете просто заменить в коде вызов одной функции на вызов другой, обернутой, и код продолжит работать без изменений, поскольку интерфейс остался прежним. В этом случае код, использующий вашу новую функцию, не заметит, что она обернута и его не потребуется переписывать. Этот подход также называется декорированием и описывается в справочниках по шаблонам проектирования как "паттерн Декоратор".</p>
11
<p>По похожей идее работают мидлвары. Они расширяют функционал обработчиков запросов, оборачивая их в подобные методы. При этом оригинальный обработчик остается неизменным</p>
11
<p>По похожей идее работают мидлвары. Они расширяют функционал обработчиков запросов, оборачивая их в подобные методы. При этом оригинальный обработчик остается неизменным</p>
12
<h2>Использование мидвар</h2>
12
<h2>Использование мидвар</h2>
13
<p>Фреймворк Slim имеет встроенную поддержку мидлвар. Для подключения мидлвар в Slim используются метод add()</p>
13
<p>Фреймворк Slim имеет встроенную поддержку мидлвар. Для подключения мидлвар в Slim используются метод add()</p>
14
<p>Рассмотрим пример кода с подключением мидлвары:</p>
14
<p>Рассмотрим пример кода с подключением мидлвары:</p>
15
<p>В приведенном примере подключена мидлвара, которая для каждого входящего запроса выводит в консоль сообщение с информацией о запросе</p>
15
<p>В приведенном примере подключена мидлвара, которая для каждого входящего запроса выводит в консоль сообщение с информацией о запросе</p>
16
<p>Каждая мидлвара представляет собой анонимную функцию, которая принимает два аргумента:</p>
16
<p>Каждая мидлвара представляет собой анонимную функцию, которая принимает два аргумента:</p>
17
<ul><li>Объект Request, который представляет собой запрос</li>
17
<ul><li>Объект Request, который представляет собой запрос</li>
18
<li>Объект RequestHandler позволяет определять, как обрабатывать входящие запросы и генерировать ответы</li>
18
<li>Объект RequestHandler позволяет определять, как обрабатывать входящие запросы и генерировать ответы</li>
19
</ul><p>Функция обязательно должна вернуть объект класса, реализующего Psr\Http\Message\ResponseInterface</p>
19
</ul><p>Функция обязательно должна вернуть объект класса, реализующего Psr\Http\Message\ResponseInterface</p>
20
<p>Каждый раз, когда мы используем add(), очередная мидлвара добавляется к приложению. Slim добавляет мидлвары в виде концентрических слоев, окружающих основное приложение. Каждая новая мидлвара окружает все существующие слои.</p>
20
<p>Каждый раз, когда мы используем add(), очередная мидлвара добавляется к приложению. Slim добавляет мидлвары в виде концентрических слоев, окружающих основное приложение. Каждая новая мидлвара окружает все существующие слои.</p>
21
<p>Когда мы запускаем приложение, объект Request обходит слои мидвар снаружи внутрь. Первым выполняется последний добавленный слой промежуточного ПО. Каждая мидлвара выполняет свою функцию, а затем передает управление следующей в цепочке</p>
21
<p>Когда мы запускаем приложение, объект Request обходит слои мидвар снаружи внутрь. Первым выполняется последний добавленный слой промежуточного ПО. Каждая мидлвара выполняет свою функцию, а затем передает управление следующей в цепочке</p>
22
<p>Сначала запрос попадает в самый внешний слой, затем в следующий слой, и так далее, пока не попадает в само приложение. После того как приложение обработает соответствующий запрос, полученный объект Response выходит из приложения и проходит по слоям мидвар ПО изнутри наружу. В конце концов, конечный объект Response выходит из внешнего промежуточного ПО, сериализуется в HTTP-ответ и возвращается клиенту</p>
22
<p>Сначала запрос попадает в самый внешний слой, затем в следующий слой, и так далее, пока не попадает в само приложение. После того как приложение обработает соответствующий запрос, полученный объект Response выходит из приложения и проходит по слоям мидвар ПО изнутри наружу. В конце концов, конечный объект Response выходит из внешнего промежуточного ПО, сериализуется в HTTP-ответ и возвращается клиенту</p>
23
<p>В примере выше мы подключили мидлвары, одна из которых выводит в консоль сообщение, а другая добавляет кастомный заголовок<em>X-Custom-Header</em>в каждый ответ.</p>
23
<p>В примере выше мы подключили мидлвары, одна из которых выводит в консоль сообщение, а другая добавляет кастомный заголовок<em>X-Custom-Header</em>в каждый ответ.</p>
24
<p>Запустим сервер и сделаем запрос:</p>
24
<p>Запустим сервер и сделаем запрос:</p>
25
<p>При этом в консоли, где запущено приложение, мы можем увидеть вывод:</p>
25
<p>При этом в консоли, где запущено приложение, мы можем увидеть вывод:</p>
26
<h2>Терминальная мидлвара</h2>
26
<h2>Терминальная мидлвара</h2>
27
<p>Далеко не всегда мы хотим двигаться вглубь по всей цепочке добавленных мидлвар. Более того, в какой-то момент одна из мидлвар должна взять обработку запроса на себя. Чтобы завершить обработку, мидлвар может создать и вернуть ответ, не передавая управление следующему мидлвару или обработчику. Это прекращает движение по цепочке, пропуская оставшиеся мидлвары для текущего запроса, и происходит отправка ответа клиенту</p>
27
<p>Далеко не всегда мы хотим двигаться вглубь по всей цепочке добавленных мидлвар. Более того, в какой-то момент одна из мидлвар должна взять обработку запроса на себя. Чтобы завершить обработку, мидлвар может создать и вернуть ответ, не передавая управление следующему мидлвару или обработчику. Это прекращает движение по цепочке, пропуская оставшиеся мидлвары для текущего запроса, и происходит отправка ответа клиенту</p>
28
<p>Такой подход полезен, когда необходимо остановить выполнение дальнейших мидлвар или маршрутов в случае ошибки аутентификации или других условий, при которых дальнейшая обработка не имеет смысла. Например, можно создать мидлвару для проверки наличия определенного параметра в запросе, и если параметр отсутствует, отправить ответ с ошибкой, пропустив выполнение остальных мидлвар и обработчиков.</p>
28
<p>Такой подход полезен, когда необходимо остановить выполнение дальнейших мидлвар или маршрутов в случае ошибки аутентификации или других условий, при которых дальнейшая обработка не имеет смысла. Например, можно создать мидлвару для проверки наличия определенного параметра в запросе, и если параметр отсутствует, отправить ответ с ошибкой, пропустив выполнение остальных мидлвар и обработчиков.</p>
29
<p>Запустим приложение и сделаем запрос:</p>
29
<p>Запустим приложение и сделаем запрос:</p>
30
<p>Видим, что выполнение остановилось на первой мидлваре и сразу вернулся ответ</p>
30
<p>Видим, что выполнение остановилось на первой мидлваре и сразу вернулся ответ</p>
31
<p>У такого поведения, когда есть цепочка функций и любая из них в процессе обработки может принять решение остановки цепочки и возврата ответа, есть имя. Такие цепочки называют<a>chain responsibility</a>, и это тоже паттерн</p>
31
<p>У такого поведения, когда есть цепочка функций и любая из них в процессе обработки может принять решение остановки цепочки и возврата ответа, есть имя. Такие цепочки называют<a>chain responsibility</a>, и это тоже паттерн</p>