Философия middleware
Рассмотрим, что такое промежуточное программное обеспечение
Что такое middleware
middleware
- это некая прослойка между запросом и непосредственно его выполнением.
По сути middleware
- это код, промежуточный слой которого навешивается на маршрут или группу маршрутов. Либо middleware
можно навесить на все приложение.
Где применяется
middleware
могут применятся в разных частях системы.
Они осуществляют роль фильтра, обработчика запросов, авторизацию и аутентификацию.
Рассмотрим их в контексте веб-сервисов или веб-приложений.
На их уровне может быть:
- Проверка роли пользователя.
- Аутентификация и авторизация пользователя.
- Шифрование.
- Обрезка пробелов в запросе.
- Проверка токена.
- Проверка на ip адрес запроса.
- Логирование и дебаг.
- обработка CORS
То есть получается, что какие-то фильтры могут быть применены для всех запросов приложения всегда. Либо применены к определенному действию или группе действий
1
2
3
Приложение
Группа действий
Действие
Принцип действия
Принцип действия middleware
можно рассмотреть на примере обычных функций в любом языке программирования.
Например, рассмотрим пример на php
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
// Функции фильтры которые будем применять к действию
function filter1($action){
// что-то делаем с данными
echo 'Применение фильтра 1'."<br>";
return $action;
}
function filter2($action){
// что-то делаем с данными
echo 'Применение фильтра 2'."<br>";
return $action;
}
function filter3($action){
// что-то делаем с данными
echo 'Применение фильтра 3'."<br>";
return $action;
}
// Действие 1
function action($action){
filter1(filter2(filter3($action)));
return 'Выполнение '. $action;
}
echo action('action');
/*
Применение фильтра 3
Применение фильтра 2
Применение фильтра 1
Выполнение action
*/
// Действие 2
function action2($action){
filter1(filter3($action));
return 'Выполнение '. $action;
}
echo action2('action');
/*
Применение фильтра 3
Применение фильтра 1
Выполнение action
*/
?>
В примере выше у нас есть набор фильтров, через которые у нас проходит запрос. На каждом этапе запрос может не пройти фильтр и вернуть ошибку.
В “действии 1”, запрос у нас пропускается через 3 фильтра, а в “действии 2” через 2 фильтра.
middleware
работают похожим образом.
Теперь посмотрим как работают реальные middleware
во фреймворке slim
.
Кто не знает, напомню что в slim
маршруты можно определять как анонимные функции.
Вот так:
1
2
3
4
5
6
7
8
9
10
<?php
use Slim\Psr7\Request;
use Slim\Psr7\Response;
// Приложение было определено заранее
// А это маршрут /test
$application->get('/test', function (Request $request, Response $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
});
?>
Теперь добавим два middleware
, на уровне одного действия методом add
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
use Slim\Psr7\Request;
use Slim\Psr7\Response;
use Psr\Http\Server\RequestHandlerInterface;
$application->get('/test', function (Request $request, Response $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
// Добавляем middleware
})->add(function (Request $request, RequestHandlerInterface $handler){
echo "one middleware for /test<br>"; return $handler->handle($request);
})->add(function (Request $request, RequestHandlerInterface $handler){
echo "two middleware for /test<br>"; return $handler->handle($request);
});
?>
В данном случае middleware
выполняются как бы наоборот, снизу вверх до контента действия, каждый раз проталкивая запрос дальше.
На каждом этапе middleware
могут вносить корректировки в запрос, модифицируя или отклоняя его.
Текст, который будет выведен:
1
2
3
two middleware for /test
one middleware for /test
/test
Теперь маршруты:
1
2
3
4
/routeGroup/test1
/routeGroup/test2
/routeGroup/subGroup1/test
/routeGroup/subGroup1/otherGroup1/test
В группы следующим образом:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$application->group('/routeGroup', function (\Slim\Routing\RouteCollectorProxy $group){
$group->get('/test1', function (Request $request, Response $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
});
$group->get('/test2', function (Request $request, Response $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
});
$group->group('/subGroup1', function (\Slim\Routing\RouteCollectorProxy $group2){
$group2->get('/test', function ($request, $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
});
$group2->group('/otherGroup1', function (\Slim\Routing\RouteCollectorProxy $group3){
$group3->get('/test', function ($request, $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
});
});
});
});
Теперь добавим к маршрутам middleware
, и посмотрим на результаты
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$application->group('/routeGroup', function (\Slim\Routing\RouteCollectorProxy $group){
$group->get('/test1', function (Request $request, Response $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
});
$group->get('/test2', function (Request $request, Response $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
})->add(function (Request $request, RequestHandlerInterface $handler){
echo "middleware for two /routeGroup/test2<br>"; return $handler->handle($request);
})->add(function (Request $request, RequestHandlerInterface $handler){
echo "middleware for one /routeGroup/test2<br>"; return $handler->handle($request);
});
$group->group('/subGroup1', function (\Slim\Routing\RouteCollectorProxy $group2){
$group2->get('/test', function ($request, $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
});
$group2->group('/otherGroup1', function (\Slim\Routing\RouteCollectorProxy $group3){
$group3->get('/test', function ($request, $response) {
echo $_SERVER['REQUEST_URI'];
return $response;
});
});
})->add(function (Request $request, RequestHandlerInterface $handler){
echo "middleware for one /routeGroup/subGroup1<br>"; return $handler->handle($request);
});
})->add(function (Request $request, RequestHandlerInterface $handler){
echo "middleware for one /routeGroup<br>"; return $handler->handle($request);
});
Результаты, что получилось:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Маршрут
/routeGroup/test1
Ответ
middleware for one /routeGroup
/routeGroup/test1
Маршрут
/routeGroup/test2
Ответ
middleware for one /routeGroup
middleware for one /routeGroup/test2
middleware for two /routeGroup/test2
/routeGroup/test2
Маршрут
/routeGroup/subGroup1/test
Ответ
middleware for one /routeGroup
middleware for one /routeGroup/subGroup1
/routeGroup/subGroup1/test
Маршрут
/routeGroup/subGroup1/otherGroup1/test
Ответ
middleware for one /routeGroup
middleware for one /routeGroup/subGroup1
/routeGroup/subGroup1/otherGroup1/test
То есть мы добавили middleware
на всю группу, на внутреннюю группу и на конкретное действие. Мы можем манипулировать как нам нужно.
Еще можно объявить глобальные middleware
, которые будут срабатывать на все маршруты.
1
2
3
4
5
<?php
$application->add(function (Request $request, RequestHandlerInterface $handler){
echo "global middleware<br>"; return $handler->handle($request);
});
?>
Плюсы и минусы
Среди плюсов можно отметить:
- Ускоряет разработку и управление проектом, так как мы используем одни и те же решения для разных контекстов.
- Дает возможность использовать одни и те же
middleware
в разных проектах. - Сокращение ошибок благодаря централизованному управлению.
Из минусов можно сказать, что, так как запрос идет через промежуточное программное обеспечение, это может замедлить работу приложения в целом.
Что в итоге
middleware
- это такой посредник, который работает с входящим запросом приложения, видоизменяет его и отправляет запрос дальше следущему middleware
. В результате доходя до действия.
С помощью middleware
, можно автоматизировать проверки, которые должны происходить при каждом запросе.
Хотите оптимизировать свой бизнес, нужен сервис, сайт или интеграция.
Бесплатно расчитаю время разработки, предложу решение вашей задачи.