Может войдёшь?
Черновики Написать статью Профиль

Middleware

перевод документация 5.х

  1. 1. Введение
  2. 2. Создание посредника
    1. 2.1. Посредник «до» и «после»
  3. 3. Регистрация посредника
    1. 3.1. Глобальный посредник
    2. 3.2. Назначение посредника для маршрутов
    3. 3.3. Группы посредников
  4. 4. Параметры посредника
  5. 5. Посредник terminable
Этот перевод актуален для англоязычной документации на (ветка 5.2) , (ветка 5.1) и (ветка 5.0). Опечатка? Выдели и нажми Ctrl+Enter.

Введение

HTTP-посредники (англ. middleware) предоставляют удобный механизм для фильтрации HTTP-запросов вашего приложения. Например, в Laravel есть посредник для проверки аутентификации пользователя. Если пользователь не аутентифицирован, посредник перенаправит его на экран входа в систему. Если же пользователь аутентифицирован, посредник позволит запросу пройти далее в приложение.

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

В Laravel есть несколько стандартных посредников, включая посредники для обслуживания, аутентификации, CSRF-защиты и многие другие. Все они расположены в каталоге app/Http/Middleware.

Создание посредника

Чтобы создать посредника, используйте команду Artisan shmake:middleware:

+ 5.2

добавлено в 5.2 ()

shphp artisan make:middleware AgeMiddleware
+ 5.1 5.0

добавлено в 5.1 () 5.0 ()

shphp artisan make:middleware OldMiddleware

Эта команда поместит новый класс AgeMiddleware (для версии 5.1 и ранее OldMiddleware) в ваш каталог app/Http/Middleware. В этом посреднике мы будем пропускать только те запросы, в которых age будет больше 200, а во всех остальных случаях будем перенаправлять пользователей на «home» URI.

PHP
<?php

namespace App\Http\Middleware;

use 
Closure;

class 
AgeMiddleware
// для версии 5.1 и ранее
// class OldMiddleware
{
  
/**
   * Выполнение фильтра запроса.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Closure  $next
   * @return mixed
   */
  
public function handle($requestClosure $next)
  {
    if (
$request->input('age') <= 200) {
      return 
redirect('home');
    }

    return 
$next($request);
  }

}

Как видите, если переданный age меньше или равен 200, то посредник вернёт клиенту переадресацию, иначе, запрос будет передан далее в приложение. Чтобы передать запрос дальше в приложение (позволяя посреднику «передать» его), просто вызовите замыкание PHP$next с параметром PHP$request.

Проще всего представить посредника как набор «уровней», которые должен пройти HTTP-запрос, прежде чем он дойдёт до вашего приложения. Каждый уровень может проверить запрос и даже вовсе отклонить его.

Посредник «до» и «после»

Момент, в который сработает посредник — до или после запроса, зависит от него самого. Например, этот посредник выполнит некоторую задачу прежде, чем запрос будет обработан приложением:

PHP
<?php

namespace App\Http\Middleware;

use 
Closure;

class 
BeforeMiddleware
{
  public function 
handle($requestClosure $next)
  {
    
// Выполнение действия

    
return $next($request);
  }
}

А этот посредник выполнит задачу после того, как запрос будет обработан приложением:

PHP
<?php

namespace App\Http\Middleware;

use 
Closure;

class 
AfterMiddleware
{
  public function 
handle($requestClosure $next)
  {
    
$response $next($request);

    
// Выполнение действия

    
return $response;
  }
}

Регистрация посредника

Глобальный посредник

Если вы хотите, чтобы посредник запускался для каждого HTTP-запроса в вашем приложении, добавьте этот посредник в свойство PHP$middleware класса app/Http/Kernel.php.

Назначение посредника для маршрутов

Если вы хотите назначить посредника для конкретных маршрутов, то сначала вам надо добавить сокращённый ключ посредника в класс app/Http/Kernel.php. По умолчанию свойство PHP$routeMiddleware этого класса содержит записи посредников Laravel. Чтобы добавить ваш собственный посредник, просто добавьте его к этому списку и присвойте ему ключ на свой выбор. Например:

PHP
// в классе App\Http\Kernel...

protected $routeMiddleware = [
  
'auth' => \App\Http\Middleware\Authenticate::class,
  
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
  
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
  
//для версии 5.2 и выше:
  
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];

Когда посредник определён в HTTP-ядре, вы можете использовать ключ middleware в массиве параметров маршрута:

PHP
Route::get('admin/profile', ['middleware' => 'auth', function () {
  
//
}]);

Используйте массив для назначения нескольких посредников для маршрута:

PHP
Route::get('/', ['middleware' => ['first''second'], function () {
  
//
}]);

Вместо использования массива вы можете использовать сцепку метода PHPmiddleware() с определением маршрута:

PHP
Route::get('/', function () {
  
//
})->middleware(['first''second']);
+ 5.2

добавлено в 5.2 ()

При назначении посредника вы можете также передать полное имя класса:

PHP
use App\Http\Middleware\FooMiddleware;

Route::get('admin/profile', ['middleware' => FooMiddleware::class, function () {
  
//
}]);

Группы посредников

Иногда бывает полезно объединить несколько посредников под одним ключом, чтобы проще назначать их на маршруты. Это можно сделать при помощи свойства PHP$middlewareGroups вашего HTTP-ядра.

Из коробки в Laravel есть группы посредников web и api, которые содержат те посредники, которые часто применяются к маршрутам веб-UI и API:

PHP
/**
 * Группы посредников маршрутов приложения.
 *
 * @var array
 */
protected $middlewareGroups = [
  
'web' => [
    \
App\Http\Middleware\EncryptCookies::class,
    \
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \
Illuminate\Session\Middleware\StartSession::class,
    \
Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \
App\Http\Middleware\VerifyCsrfToken::class,
  ],

  
'api' => [
    
'throttle:60,1',
    
'auth:api',
  ],
];

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

PHP
Route::group(['middleware' => ['web']], function () {
  
//
});

Не забывайте, группа посредников web автоматически применяется к вашему стандартному файлу routes.php сервис-провайдером RouteServiceProvider.

Параметры посредника

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

Дополнительные параметры посредника будут передаваться в посредник после аргумента PHP$next:

PHP
<?php

namespace App\Http\Middleware;

use 
Closure;

class 
RoleMiddleware
{
  
/**
   * Выполнение фильтрации запроса.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Closure  $next
   * @param  string  $role
   * @return mixed
   */
  
public function handle($requestClosure $next$role)
  {
    if (! 
$request->user()->hasRole($role)) {
      
// Redirect...
    
}

    return 
$next($request);
  }

}

Параметры посредника можно указать при определении маршрута, отделив название посредника от параметров двоеточием :. Сами параметры разделяются запятыми:

PHP
Route::put('post/{id}', ['middleware' => 'role:editor', function ($id) {
  
//
}]);

Посредник terminable

Иногда посредник должен выполнить некоторые действия уже после отправки HTTP-ответа браузеру. Например, посредник «session», поставляемый с Laravel, записывает данные сессии в хранилище после отправки ответа в браузер. Для этого нужно определить посредника как «terminable», добавив в него метод PHPterminate():

PHP
<?php

namespace Illuminate\Session\Middleware;

use 
Closure;

class 
StartSession
{
  public function 
handle($requestClosure $next)
  {
    return 
$next($request);
  }

  public function 
terminate($request$response)
  {
    
// Сохранение данных сессии...
  
}

}

Метод PHPterminate() получает и запрос, и ответ. Определив посредника как «terminable», вы должны добавить его в список глобальных посредников в вашем HTTP-ядре.

При вызове метода PHPterminate() в посреднике, Laravel получит свежий экземпляр посредника из сервис-контейнера. Если вы хотите использовать тот же самый экземпляр посредника при вызовах методов PHPhandle() и PHPterminate(), зарегистрируйте посредника в контейнере при помощи метода PHPsingleton().

Комментарии (4)

potMaster

Не совсем понятно про посредников «до» и «после». У них имена просто должны начинаться с «Before» и «After» соответственно ?

IceJOKER

Внимательно посмотрите на тело метода, в одном сначала идет выполнение кода, а потом передаем дальше, а во втором сначала передаем дальше, а потом выполняем код. http://joxi.ru/xAee68Wt57Q6Ay - на скрине, думаю, будет чуть понятнее

Arni

Во-втором случае, правильнее было бы написать не «сначала передаем дальше, а потом выполняем код», а «сначала обрабатывается запрос, потом выполняется код посредника», т.к. запрос передается дальше в обоих случаях в конце с помощью return.

nko

Действительно сбивает заголовок «Посредник «до» и «после»» а после него

PHPclass BeforeMiddleware
...
PHPclass AfterMiddleware
...
У меня возникло недопонимание которое решилось после прочтения комментариев.

Может быть лучше переименовать заголовок «Посредник «до» и «после»» в «момент срабатывания посредника», а фразу «Момент, в который сработает посредник — до или после запроса, зависит от него самого.»
на «Момент, в который сработает посредник указывается в PHPfunction handle. И если нам необходимо выполнить действия до запроса, то необходимо их выполнить перед PHP$response $next($request);»

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.