Laravel 文档阅读:中间件

简介


中间件用来过滤项目中的 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 方法注册中间件了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容

  • Laravel 学习交流 QQ 群:375462817 本文档前言Laravel 文档写的很好,只是新手看起来会有...
    Leonzai阅读 7,898评论 2 12
  • Laravel框架一:原理机制篇 Laravel作为在国内国外都颇为流行的PHP框架,风格优雅,其拥有自己的一些特...
    Mr_Z_Heng阅读 3,684评论 0 13
  • 中间件 简介 HTTP 中间件为你的应用提供了一种便利的机制去过滤客户端的请求,比如说laravel中自带的用来验...
    Dearmadman阅读 1,905评论 3 2
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,654评论 18 139
  • 介绍 Laravel 是一款 MVC架构、 目前最流行的 PHP框架。 Laravel的优点在于: 丰富的comp...
    那就远走阅读 7,770评论 3 18