ミドルウエア

この記事は自分の勉強のために書いています。
ソースはLaravel5.7の公式ドキュメントです。
新しいことは何もないので通常はそちらを参照してください。


アプリケーションに送られてきたリクエストを途中でフィルタするのがミドルウェア。
認証とかCORSとかCSRFとか、デフォルトでミドルウェアが用意されているけれども、
ミドルウェアを自作することができる。

ミドルウェアの定義

新しいミドルウェアの作成

ミドルウェアを作成するartisanコマンドは以下の通り。
こうすると、app/Http/Middlewareの中にCheckCostクラスが作られる。


$ php artisan make:middleware CheckCost;

CheckCostクラスの中でhandle()メソッドを実装する。
$requestを$nextに流す際に$closureを評価するように動作し、
結果として$requestと$nextの間のフィルタ処理を$closureに書くことができる。


<?php
namespace App\Http\Middleware;
use Closure;
class CheckCost
{
    /**
     *   送信されたきたリクエストをフィルタする
     *
     *   @param \Illuminate\Http\Request $request
     *   @param \Closure $next
     *   @return mixed
    */
    public function handle($request, $closure $next)
    {
         if ($request->value < 100)
         {
              return redirect('hoge');
         }
         return $next($request);
    }
}

ミドルウェアを複数使用するとき、
前の段のミドルウェアを通過した後、次の段のミドルウェアを通過する。

Before Middleware/ After Middleware

公式だと仰々しい名前が付いているのだけれども、
$nextを呼んだ後に処理をするか、呼ぶ前に処理をするか、の違いを表現できる。
つまり、リクエストを完了する前の処理なのか、後の処理なのか。


<?php
namespace App\Http\Middleware;
use Closure;
class CheckCost
{
    /**
     *   Before Middleware
     *   リクエストを評価する前に処理する
     *
     *   @param \Illuminate\Http\Request $request
     *   @param \Closure $next
     *   @return mixed
    */
    public function handle($request, $closure $next)
    {
         //アクションを実行
         return $next($request);
    }
}


namespace App\Http\Middleware;
use Closure;
class CheckCost
{
    /**
     *   After Middleware
     *   リクエストを評価した後に処理する
     *
     *   @param \Illuminate\Http\Request $request
     *   @param \Closure $next
     *   @return mixed
    */
    public function handle($request, $closure $next)
    {
         $response = $next($request);
         return $response;
    }
}

登録

グローバルミドルウェア

要は全てのHTTPリクエストについてミドルウェアを通すやり方。
App/Http/Kernel.phpに書く。Kernelクラスにある$middlewareという配列に
グローバルミドルウェアにしたいやつを並べていく。


<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
    protected $middleware = [
        ...
    ]
}

特定のルートのみにミドルウェアを設定

特定のルートに限定してミドルウェアを設定する場合もApp/Http/Kernel.phpに書く。
まず、$routeMiddlewareにミドルウェアの短縮キーを書く


<?php
   $routeMiddleware = [
      'auth' => \App\Http\Middleware\Authenticate::class,
      'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,

      ...
   ];

そして、routes.phpでそれぞれのルートに定義した短縮キーを指定する。
短縮キーではなく完全なクラス名を書いても良いみたい。
ミドルウェアを複数書くと、その順番に通すことになる。


Route::get('admin/profile', function() {

})->middleware('auth');
Route::get2('admin/profile2', function() {

})->middleware('CheckCost::class');
Route::get3('admin/profile3', function() {

})->middleware('auth','guest');

ミドルウェアグループ

複数のミドルウェアをグループ化して、そのグループのミドルウェアを一気に当てることができる。
App/Http/Kernel.phpに書く。Kernelクラスにある$middlewareGroupという配列に
グループ名をキー、ミドルウェアの配列を値として書いていく。以下のように。


<?php
   $middlewareGroup = [
      'web' => [
         'auth' => \App\Http\Middleware\Authenticate::class,
         'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
         ...
      ],
      ...
   ];

routes.phpの中では、それぞれのルートに定義したグループ名を与える。
例えば、以下だと'/'に対して'web'ミドルウェアグループを与えている。
つまり'/'に'web'ミドルウェアグループに定義したミドルウェアが順番にあたる。


Route::get('/',function(){

})->middleware('web');

routes/web.php に書いたルートには自動的に'web'ミドルウェアグループがあたる。

ミドルウェアパラメタ

ミドルウェアパラメタの書き方

ミドルウェア実行時に引数を与えることができる。
書き方は以下の通り。handle()をオーバーライドする際に、引数として受けるパラメタを追加する。
例えば、パラメタ$paramを受け取るミドルウェアは以下の通り。
クエリパラメタにある$valが$paramである場合に限り処理を書いている。


<?php
namespace App\Http\Middleware;
use Closure;
class CheckCost
{
    /**
     *   送信されたきたリクエストをフィルタする
     *
     *   @param \Illuminate\Http\Request $request
     *   @param \Closure $next
     *   @return mixed
    */
    public function handle($request, $closure $next, $param)
    {
         if ($request->val == $param)
         {
              return redirect('hoge');
         }
         return $next($request);
    }
}

ミドルウェア指定時に以下のようにパラメタを渡す。
T.B.D.

終了処理ミドルウェア

T.B.D.

サンプル

実行時間を計測するミドルウェアの試作

こちらを参考に試しに作ってみた。
https://qiita.com/niisan-tokyo/items/663300f8df1c6c89f0ae


$ php artisan make:middleware TimerMiddleware
Middleware created successfully.

TimerMiddleware本体はこちら。


<?php

namespace App\Http\Middleware;

use Closure;

class TimerMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $before = microtime(true);
        $res = $next($request);
        \Log::debug(mictotime(true) - $before);
        return $res;
    }
}

ミドルウェアの登録は、app/Http/Kernel.phpの$routeMiddlewareに追加。


protected $routeMiddleware = [
   ..
   \App\Http\Middleware\TimerMiddleware::class,
];

ルートの定義はこちら。


Route::get('timer',function(){

})->middleware('timer');

/timer にアクセスすると、storages/logs/laravel.logにログが残る。


...
[2019-01-29 16:05:07] local.DEBUG: 0.019489049911499