1、简介

HTTP 中间件为过滤进入应用的 HTTP 请求提供了一套便利的机制。例如,Laravel 内置了一个中间件来验证用户是否经过授权,如果用户没有经过授权,中间件会将用户重定向到登录页面,否则如果用户经过授权,中间件就会允许请求继续往前进入下一步操作。

当然,除了认证之外,中间件还可以被用来处理更多其它任务。比如:CORS 中间件可以用于为离开站点的响应添加合适的头(跨域);日志中间件可以记录所有进入站点的请求。

Laravel框架自带了一些中间件,包括维护模式、认证、CSRF 保护中间件等等。所有的中间件都位于app/Http/Middleware 目录。

2、定义中间件

要创建一个新的中间件,可以通过 Artisan 命令 make:middleware

php artisan make:middleware CheckAge

这个命令会在 app/Http/Middleware 目录下创建一个新的中间件类 CheckAge,在这个中间件中,我们只允许提供的 age 大于 200 的请求访问路由,否则,我们将用户重定向到 home

<?php

namespace App\Http\Middleware;

use Closure;
class CheckAge
{
/**
* 返回请求过滤器
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->input('age') <= 200) {
return redirect('home');
} return $next($request);
} }

正如你所看到的,如果 age<=200,中间件会返回一个 HTTP 重定向到客户端;否则,请求会被传递下去。将请求往下传递可以通过调用回调函数 $next 并传入  $request

理解中间件的最好方式就是将中间件看做 HTTP 请求到达目标动作之前必须经过的“层”,每一层都会检查请求并且可以完全拒绝它。

中间件之前/之后

一个中间件是请求前还是请求后执行取决于中间件本身。比如,以下中间件会在请求处理前执行一些任务:

<?php

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware
{
public function handle($request, Closure $next)
{
// 执行动作 return $next($request);
}
}

然而,下面这个中间件则会在请求处理后执行其任务:

<?php

namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request); // 执行动作 return $response;
}
}
3、注册中间件
全局中间件

如果你想要中间件在每一个 HTTP 请求期间被执行,只需要将相应的中间件类设置到 app/Http/Kernel.php 的数组属性 $middleware 中即可。

分配中间件到路由

如果你想要分配中间件到指定路由,首先应该在 app/Http/Kernel.php 文件中分配给该中间件一个简写的 key,默认情况下,该类的 $routeMiddleware 属性包含了 Laravel 内置的入口中间件,添加你自己的中间件,只需要将其追加到后面并为其分配一个 key,例如:

// Within App\Http\Kernel Class...

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

中间件在 HTTP Kernel 中被定义后,可以使用 middleware 方法将其分配到路由:

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

使用数组分配多个中间件到路由:

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

分配中间件的时候还可以传递完整的类名:

use App\Http\Middleware\CheckAge;

Route::get('admin/profile', function () {
//
})->middleware(CheckAge::class);
中间件组

有时候你可能想要通过指定一个键名的方式将相关中间件分到同一个组里面,从而更方便将其分配到路由中,这可以通过使用 HTTP Kernel 的 $middlewareGroups  属性实现。

Laravel 自带了开箱即用的 webapi 两个中间件组以包含可以应用到 Web UI 和 API 路由的通用中间件:

/**
* The application's route middleware groups.
*
* @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',
],
];

中间件组可以被分配给路由和控制器动作,使用和单个中间件分配同样的语法。再次申明,中间件组的目的只是让一次分配给路由多个中间件的实现更加简单:

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

注:默认情况下, RouteServiceProvider 自动将中间件组 web 应用到 routes/web.php 文件。

4、中间件参数

中间件还可以接收额外的自定义参数,例如,如果应用需要在执行给定动作之前验证认证用户是否拥有指定的角色,可以创建一个 CheckRole 来接收角色名作为额外参数。

额外的中间件参数会在 $next 参数之后传入中间件:

<?php

namespace App\Http\Middleware;

use Closure;
class CheckRole
{
/**
* 运行请求过滤器
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $role
* @return mixed
* translator http://laravelacademy.org
*/
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// Redirect...
} return $next($request);
} }

中间件参数可以在定义路由时通过:分隔中间件名和参数名来指定,多个中间件参数可以通过逗号分隔:

Route::put('post/{id}', function ($id) {
//
})->middleware('role:editor');
5、可终止的中间件

有时候中间件可能需要在 HTTP 响应发送到浏览器之后做一些工作。比如,Laravel 内置的“session”中间件会在响应发送到浏览器之后将 Session 数据写到存储器中,为了实现这个功能,需要定义一个可终止的中间件并添加 terminate 方法到这个中间件:

<?php

namespace Illuminate\Session\Middleware;

use Closure;

class StartSession
{
public function handle($request, Closure $next)
{
return $next($request);
} public function terminate($request, $response)
{
// 存储session数据...
}
}

terminate 方法将会接收请求和响应作为参数。定义了一个可终止的中间件之后,还需要将其加入到 HTTP kernel 的全局中间件列表中。

当调用中间件上的 terminate 方法时,Laravel 将会从服务容器中取出该中间件的新的实例,如果你想要在调用handleterminate 方法时使用同一个中间件实例,则需要使用容器的 singleton 方法将该中间件注册到容器中。

HTTP层 —— 中间件的更多相关文章

  1. Express中间件

    一.编写中间件 中间件函数能够访问请求对象(req),响应对象(res),应用程序的请求/响应循环中的下一个中间件函数.下一个中间件函数通常由名为next的变量来表示. 中间件函数可以执行以下任务: ...

  2. MTDDL 美团分布式数据访问中间件(转)

    MTDDL 美团分布式数据访问中间件(转) 原文地址:MTDDL--美团点评分布式数据访问层中间件 因原文文字和图显示有问题,故整理于此,仅供参考. 业界方案 组件 简介 Atlas Qihoo 36 ...

  3. 复杂分布式架构下的计算治理之路:计算中间件 Linkis

    前言 在当前的复杂分布式架构环境下,服务治理已经大行其道.但目光往下一层,从上层 APP.Service,到底层计算引擎这一层面,却还是各个引擎各自为政,Client-Server 模式紧耦合满天飞的 ...

  4. Redis集群最佳实践

    今天我们来聊一聊Redis集群.先看看集群的特点,我对它的理解是要需要同时满足高可用性以及可扩展性,即任何时候对外的接口都要是基本可用的并具备一定的灾备能力,同时节点的数量能够根据业务量级的大小动态的 ...

  5. hiberante入门

    Hibernate 目前企业级应用一般均采用面向对象的开发方法,而内存中的对象数据不能永久存在,如想借用关系数据库来永久保存这些数据的话,无疑就存在一个对象-关系的映射过程.在这种情形下,诞生了许多解 ...

  6. Java开源 开源工作流

    OpenEbXML   点击次数7801 Werkflow   点击次数11181 OSWorkflow   点击次数14988 wfmOpen   点击次数7997 OFBiz   点击次数1234 ...

  7. 实例详解 EJB 中的六大事务传播属性--转

    前言 事务 (Transaction) 是访问并可能更新数据库中各种数据项的一个程序执行单元 (unit).在关系数据库中,一个事务可以是一条或一组 SQL 语句,甚至整个程序.它有通常被称为 ACI ...

  8. 从头编写 asp.net core 2.0 web api 基础框架 (1)

    工具: 1.Visual Studio 2017 V15.3.5+ 2.Postman (Chrome的App) 3.Chrome (最好是) 关于.net core或者.net core 2.0的相 ...

  9. 【转载】从头编写 asp.net core 2.0 web api 基础框架 (1)

    工具: 1.Visual Studio 2017 V15.3.5+ 2.Postman (Chrome的App) 3.Chrome (最好是) 关于.net core或者.net core 2.0的相 ...

随机推荐

  1. matlab 函数说明—ordfilt2

    今天看harris角点实现的源码,在某一个版本中看到了这个函数,不是很理解,doc ordfilt2之后还是不清楚,终于在matlab论坛上搞清楚了ordfilt2的功能.   中文理解函数名就是顺序 ...

  2. C#中克隆随机数的三种方法(为什么我想到了茴字的四种写法

    C#中的Random类可以用来产生伪随机数(正确的废话 伪随机数的一个性质就是给定一个初始种子,那么产生的随机数列都是相同的,这个性质非常适合用在不同环境之间同步逻辑的场景. 最近有一个要克隆当前随机 ...

  3. 机器学习-----线性回归浅谈(Linear Regression)

    Linear Regreesion          在现实生活中普遍存在着变量之间的关系,有确定的和非确定的.确定关系指的是变量之间可以使用函数关系式表示,还有一种是属于非确定的(相关),比如人的身 ...

  4. android sqlite 中存储 long 数据

    在資料庫的技術中,一個資料庫(Database)表示應用程式儲存與管理資料的單位,應用程式可能需要儲存很多不同的資料,例如一個購物網站的資 料庫,就需要儲存與管理會員.商品和訂單資料.每一種在資料庫中 ...

  5. hdu4123-Bob’s Race(树形dp+rmq+尺取)

    题意:Bob想要开一个运动会,有n个房子和n-1条路(一棵树),Bob希望每个人都从不同的房子开始跑,要求跑的尽可能远,而且每条路只能走最多一次.Bob希望所有人跑的距离的极差不大于q,如果起点的编号 ...

  6. 【转】可执行程序包括BSS段、数据段、代码段

    可执行程序包括BSS段.数据段.代码段(也称文本段). 一.BSS BSS(Block Started by Symbol)通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域.特点是:可 ...

  7. 第十三章、学习 Shell Scripts 善用判断式

    善用判断式 利用 test 命令的测试功能 我要检查 /dmtsai 是否存在时,使用: [root@www ~]# test -e /dmtsai [root@www ~]# test -e /dm ...

  8. OpenCV学习笔记:MAT解析

    在2001年刚刚出现的时候,OpenCV基于 C 语言接口而建.为了在内存(memory)中存放图像,当时采用名为 IplImage 的C语言结构体,时至今日这仍出现在大多数的旧版教程和教学材料.但这 ...

  9. js为select添加option

    <select id="shi"> function loadInfo(){ var shengId=document.getElementById("she ...

  10. webServices

    引用项目的配置文件: <system.serviceModel> <bindings> <basicHttpBinding> <!--旅游供应--> & ...