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

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.3) , (ветка 5.2) , (ветка 5.1) и (ветка 5.0). Опечатка? Выдели и нажми Ctrl+Enter.

Введение

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

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

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

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

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

shphp artisan make:middleware CheckAge

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

PHP
<?php

namespace App\Http\Middleware;

use 
Closure;

class 
CheckAge
{
  
/**
   * Обработка входящего запроса.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Closure  $next
   * @return mixed
   */
  
public function handle($requestClosure $next)
  {
    if (
$request->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.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
  
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
  
//для версии 5.2 и выше:
  
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
  
//для версии 5.3 и выше:
  
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
  
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
  
'can' => \Illuminate\Auth\Middleware\Authorize::class,
  
//для версии 5.2 и ранее:
  
'auth' => \App\Http\Middleware\Authenticate::class,
];
+ 5.3

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

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

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

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

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

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

Когда посредник определён в 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']);

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

PHP
use App\Http\Middleware\CheckAge;

Route::get('admin/profile', function () {
  
//
})->middleware(CheckAge::class);
+ 5.3 5.2

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

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

Иногда бывает полезно объединить несколько посредников под одним ключом, чтобы проще назначать их на маршруты. Это можно сделать при помощи свойства 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,
    \
Illuminate\Routing\Middleware\SubstituteBindings::class,
  ],

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

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

PHP
Route::get('/', function () {
  
//
})->middleware('web');

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

Группа посредников web автоматически применяется к вашему файлу routes/web.php сервис-провайдером RouteServiceProvider.

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

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

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

PHP
<?php

namespace App\Http\Middleware;

use 
Closure;

class 
CheckRole
{
  
/**
   * Обработка входящего запроса.
   *
   * @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);
  }

}

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

+ 5.3

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

PHP
Route::put('post/{id}', function ($id) {
  
//
})->middleware('role:editor');
+ 5.2 5.1 5.0

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

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

Посредник terminable

Иногда посредник должен выполнить некоторые действия уже после отправки HTTP-отклика браузеру. Например, посредник «session», поставляемый с Laravel, записывает данные сессии в хранилище после отправки ответа в браузер. Если вы определите метод 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);»

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

Разметка: ? ?

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