美文网首页
Laravel 文档阅读:中间件

Laravel 文档阅读:中间件

作者: 晨曦入诗 | 来源:发表于2018-10-06 23:33 被阅读12次

    简介


    中间件用来过滤项目中的 HTTP 请求,实际上 Laravel 项目中大量使用了中间件。例如,Laravel 中有一个验证用户是否认证的中间件,如果没有认证,就跳转到登录页面;如果认证了就进一步操作。
    当然,中间件的作用不只是在认证上。CORS 中间件负责给项目中的相应设定正确的头部(Headers);日志中的中间件负责人记录项目中处理的所有请求信息。
    Laravel 框架中包含了几种中间件,包括负责处理认证和 CSRF 保护的。所有中间件位于 app/Http/Middleware 目录下。

    定义中间件

    使用 Artisan 命令 make:middleware 创建中间件:

    php artisan make:middleware CheckAge
    

    这个命令会在 app/Http/Middleware 目录下创建一个 CheckAge 类。在这个中间件里,我么设定年龄大于18岁的可以进一步操作,小于等于18岁的重定向到用户控制台地址/home

    <?php
    namespace app/Http/Middleware
    
    use Closure;
    class CheckAge 
    {
     /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
         public function handle($request, Closure $next){
          if( $request->age <=18){
           return redirect('/home');
           }
           return $next($request);
         }
    }
    

    允许请求的进一步操作,只需将请求实例 $request 放入 $next 中即可。
    可以把中间件设想成,在最终要达到执行的业务代码前的一层层 「过滤网」,请求必须通过所有的中间件才能达到最终要执行的业务逻辑,否则被中间任何一个中间件拒绝,都会导致请求失败的。

    中间件处理时机

    一个中间件在处理请求之前或者之后进行任务处理,取决于中间件的代码逻辑放置的位置。 例如,下面的中间件在处理请求 “之前” 进行了一些任务操作:

    <?php
    namespace App/Http/Middleware;
    
    use Closure;
    class BeforeMiddleware
    {
           public function handle($request, Closure $next)
            {
              //Perform action
               return $next( $request);
             }
    }
    

    而下面的中间件是在处理请求 “之后” 才进行的任务操作:

    <?php
    namespace App/Http/Middleware;
    use Closure;
    class AfterMiddleware
    {
         public function handle($request, Closure $next)
        {
           $response = $next($request);
          //Perform action
          return $response;
        }
    }
    

    注册中间件


    全局中间件

    如果一个中间件在每次的 HTTP 请求时都要用到,那么把他列入 app/Http/Kernel.php$middleware 数组中即可。列入 $middleware 数组中的中间件又称为全局中间件。

    为路由使用中间件

    使用在路由身上的中间件是在 app/Http/Kernel.php 中的 $routeMiddleware 数组属性中定义的。如果你创建了一个新的给路由使用的中间件,就需要将他添加到 $routeMiddleware 这个数组里,并给中间件一个 key ——相当于中间件的名字。

    // Within App/Http/Kenerl class····
    
    protected $routeMiddleware = [
          'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
          'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth:class,
          'bindings' => \Illuminate\Auth\Middleware\SubstituteBinding:class,
          'can' => \Illuminate\Auth\Middleware\Authorize::class,
          'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
          'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    ];
    

    使用中间件时,就用到了这个 Key:

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

    也可以在一个路由上使用多个中间件:

    Route::get('/', function(){
    //
    })->middleware('first', 'second');
    

    也可以使用中间件的包含命名空间的完整类名(又称完全限定类名)使用中间件:

    use App\Http\Middleware\CheckAge;
    
    Route::get('admin/profile', function(){
    //
    })->middleware(CheckAge::class);
    

    中间件组

    中间件组中包含多个中间件,但它的使用和中间件是完全一样的。中间件组在 app/Http/Kenerl.php 中的 $middlewareGroups 属性中定义,每个中间件组还有一个对应的 key。
    Laravel 项目中预设并使用了两个中间件组:webapi,它们分别用在了 routes/web.phproutes/api.php 上,前者是定义 Web 接口的地方,后者是定义 Api 接口的地方。这两个类型的接口,都有一些通用的中间件,所以放到一个组里进行管理。

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroup = [
      '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',  
    ],
    ];
    

    已经说过中间件组和中间件的使用是完全一样的,不过带来一个好处——一次定义,即可使用多个中间件。中间件组可以分配给路由和控制器 action使用:

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

    注意,routes/web.php 文件里的中间件已将默认使用 web 中间件组,这是在 RouteServiceProvider 中定义的,在 routes/web.php 中定义路由时,时无需为路由额外分配 web 中间件组的。

    中间件参数


    可以为中间件传递参数。如果系统有一个需求——需要在验证角色之后才允许认证用户的进一步操作。以下以 CheckRole 中间件为例,它接受一个角色名作为参数。
    中间件参数在 handle 方法的 $next参数之后定义。

    <?php
    namespace App\Http\Middleware;
    
    use Closure;
    class CheckRole 
    {
    /**
         * Handle the incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @param  string  $role
         * @return mixed
         */
        public function handle($request, Closure $next)
         {
          if ($ $request->user()->hasRole($role)){
                   ..Redirect        
            }
          return $next($request);
        }
    }
    

    使用中间件参数的方式是在中间件后面加上一个 : ,然后在 : 后面跟上你要传递给中间件的参数。

    Route::put('post/{id}',function(){
    //
    })->middleware('role:editor');
    

    在 Http 响应之后......


    有时,中间件需要在 HTTP 响应请求之后才做处理工作。例如,包含在 Laravel 中的会话中间件会在响应发送到浏览器之后,再次保存会话数据。针对这样的需求,需要在中间件定义一个 terminate 方法,它会在响应发送到浏览器之后自动被调用。

    <?php
     namespace Illuminate\Session\Middleware;
    
    use Closure;
    class StartSession
    {
       public function handle($request, Closure $next){
         return $next($request);
       }
    
    public function terminate($request, $response)
    {
    // Store the session data....
      }
    }
    

    terminate 方法接受两个参数,请求实例和响应实例。定义好之后,将它放在 app/Http/Kernel.php 添加在中间件列表中即可。
    在调用 terminate 方法时,Laravel 是从服务容器中找到并创建一个新的中间件实例使用的,如果你只要使用同一个中间件实例,那么就要使用容器的 singleton 方法注册中间件了。

    相关文章

      网友评论

          本文标题:Laravel 文档阅读:中间件

          本文链接:https://www.haomeiwen.com/subject/ustkaftx.html