[ Laravel 5.5 文档 ] 处理用户请求 —— HTTP 请求的过滤器:中间件
[ Laravel 5.5 文档 ] 处理用户请求 —— HTTP 请求的过滤器:中间件
http://laravelacademy.org/post/7812.html
简介
中间件为过滤进入应用的 HTTP 请求提供了一套便利的机制。例如,Laravel 内置了一个中间件来验证用户是否经过认证(如登录),如果用户没有经过认证,中间件会将用户重定向到登录页面,而如果用户已经经过认证,中间件就会允许请求继续往前进入下一步操作。
当然,除了认证之外,中间件还可以被用来处理很多其它任务。比如:CORS 中间件可以用于为离开站点的响应添加合适的头(跨域);日志中间件可以记录所有进入站点的请求,从而方便我们构建系统日志系统。
Laravel 框架自带了一些中间件,包括认证、CSRF 保护中间件等等。所有的中间件都位于 app/Http/Middleware
目录下。
这篇教程将重点讲述中间件的定义、注册和使用。
定义中间件
要创建一个新的中间件,可以通过 Artisan 命令 make:middleware
:
php artisan make:middleware CheckToken
这个命令会在 app/Http/Middleware
目录下创建一个新的中间件类 CheckToken
,在这个中间件中,我们只允许提供的 token
等于指定值 laravelacademy.org
的请求访问路由,否则,我们将跳转到 Laravel 学院网站:

正如你所看到的,如果 token != 'laravelacademy.org'
,中间件会返回一个 HTTP 重定向到 Laravel 学院;否则,请求会被传递下去。将请求往下传递可以通过调用回调函数 $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;
}
}
注册中间件
中间件分三类,分别是全局中间件、中间件组和指定路由中间件:
全局中间件
如果你想要定义的中间件在每一个 HTTP 请求时都被执行,只需要将相应的中间件类添加到 app/Http/Kernel.php
的数组属性 $middleware
中即可:

但除非真的需要,否则我们一般不会把业务级别的中间件放到全局中间件中。
分配中间件到指定路由
如果你想要分配中间件到指定路由,首先应该在 app/Http/Kernel.php
文件中分配给该中间件一个 key
,默认情况下,该类的 $routeMiddleware
属性包含了 Laravel 自带的中间件,要添加你自己的中间件,只需要将其追加到后面并为其分配一个 key
,例如:
// 在 App\Http\Kernel 类中...
/**
* 应用的路由中间件列表
*
* 这些中间件可以分配给路由组或者单个路由
*
* @var array
*/
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,
'token' => CheckToken::class
];
中间件在 HTTP Kernel 中被定义后,可以使用 middleware
方法将其分配到路由:
Route::get('/', function () {
//
})->middleware('token');
这样,当我们在浏览器中访问 http://blog.dev
时就会跳到 http://laravelacademy.org
,只有当访问http://blog.dev?token=laravelacademy.org
时才能看到如下效果:

可以使用数组分配多个中间件到路由:
Route::get('/', function () {
//
})->middleware('token', 'auth');
分配中间件的时候还可以传递完整的类名(不过不推荐这种方式):
use App\Http\Middleware\CheckToken;
Route::get('admin/profile', function () {
//
})->middleware(CheckToken::class);
中间件组
有时候你可能想要通过指定一个键名的方式将相关中间件分到同一个组里面,这样可以更方便地将其分配到路由中,这可以通过使用 HTTP Kernel 提供的 $middlewareGroups
属性实现。
Laravel 自带了开箱即用的 web
和 api
两个中间件组,分别包含可以应用到 Web 和 API 路由的通用中间件:
/**
* 应用的中间件组
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
中间件组使用和分配单个中间件同样的语法被分配给路由和控制器动作。再次申明,中间件组的目的只是让一次分配给路由多个中间件的实现更加方便:
Route::get('/', function () {
//
})->middleware('web');
Route::group(['middleware' => ['web']], function () {
//
});
默认情况下, RouteServiceProvider
自动将中间件组 web
应用到 routes/web.php
文件,将中间件组 api
应用到routes/api.php
:

当然我们可以自己设置自己的中间件组,以实现更灵活的中间件分配策略:
/**
* 应用的中间件组.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
'blog' => [
'token',
]
];
我们修改 routes/web.php
下面的中间件分配方式:
Route::group(['middleware'=>['blog']],function(){
Route::get('/', function () {
return view('welcome', ['website' => 'Laravel']);
});
Route::view('/view', 'welcome', ['website' => 'Laravel学院']);
});
这样我们访问 http://blog.dev
和 http://blog.dev/view
的时候都要带上 token=laravelacademy.org
参数,否则就会跳转到 Laravel 学院网站。
中间件参数
中间件还可以接收额外的自定义参数,例如,如果应用需要在执行给定动作之前验证认证用户是否拥有指定的角色,可以创建一个 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');
根据上面的演示示例,这个功能实现起来也比较简单,就不再单独演示了。
终端中间件
终端中间件,可以理解为一个善后的后台处理中间件。有时候中间件可能需要在 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
方法将会接收请求和响应作为参数。定义了一个终端中间件之后,还需要将其加入到app/Http/Kernel.php
文件的全局中间件列表中。
当调用中间件上的 terminate
方法时,Laravel 将会从服务容器中取出一个该中间件的新实例,如果你想要在调用handle
和 terminate
方法时使用同一个中间件实例,则需要使用容器提供的 singleton
方法以单例的方式将该中间件注册到容器中。关于服务容器我们就会在后面讲到,暂时不深入展开了。
[ Laravel 5.5 文档 ] 处理用户请求 —— HTTP 请求的过滤器:中间件的更多相关文章
- [ Laravel 5.5 文档 ] 底层原理 —— 一次 Laravel 请求的生命周期
Posted on 2018年3月5日 by 学院君 简介 当我们使用现实世界中的任何工具时,如果理解了该工具的工作原理,那么用起来就会得心应手,应用开发也是如此.当你理解了开发工具如何工作,用起 ...
- [ Laravel 5.5 文档 ] 快速入门 —— 目录结构篇
简介 Laravel 默认的目录结构试图为不管是大型应用还是小型应用提供一个良好的起点.当然,你也可以按照自己的喜好重新组织应用的目录结构,因为 Laravel 对于指定类在何处被加载没有任何限制 — ...
- Laravel 5.5 文档 ] 快速入门 —— 安装配置篇
服务器要求 Laravel 框架对PHP版本和扩展有一定要求,不过这些要求 Laravel Homestead 都已经满足了,不过如果你没有使用 Homestead 的话(那真是一件很遗憾的事情),有 ...
- [ Laravel 5.3 文档 ] 安全 ―― API认证(Passport)保障安全性。
1.简介 Laravel通过传统的登录表单已经让用户认证变得很简单,但是API怎么办?API通常使用token进行认证并且在请求之间不维护session状态.Laravel使用LaravelPassp ...
- SpringBoot整合knife4j框架(可生成离线接口文档),并设置接口请求头token默认值
功能和swagger类似 官网地址:https://doc.xiaominfo.com/knife4j/ 这个框架可以设置返回字段的描述 引入依赖 <dependency> <gro ...
- Laravel 5.1 文档攻略 —— Eloquent:模型对象序列化
在写api的时候,数据一般是以json格式进行传输的,没有对象可以直接使用.这个时候,对数据的序列化转换就很重要,Eloquent提供了很方便的方法和约定,不仅可以转换,还可以控制里面的键值. 基本用 ...
- [ Laravel 5.5 文档 ] 数据库操作 —— 在 Laravel 中轻松实现分页功能
 简介 在其他框架中,分页是件非常痛苦的事,Laravel 让这件事变得简单易于上手.Laravel 的分页器与查询构建器和 Eloquent ORM 集成在一起,并开箱提供方便的.易于使用的.基于 ...
- [ Laravel 5.6 文档 ]laravel数据库操作分页(自定义分页实现和自定义分页样式)
简介 在其他框架中,分页可能是件非常痛苦的事,Laravel 让这件事变得简单.易于上手.Laravel 的分页器与查询构建器和 Eloquent ORM 集成在一起,并开箱提供方便的.易于使用的.基 ...
- [ Laravel 5.1 文档 ] 服务 —— 帮助函数
http://laravelacademy.org/post/205.html 1.简介 Laravel自带了一系列PHP帮助函数,很多被框架自身使用,然而,如果你觉得方便的话也可以在应用中随心所欲的 ...
随机推荐
- 【转】Linux磁盘文件系统类型
1. 查询命令 [root@mail ~]# df -Th 参数说明: -T 显示文件系统类型. -h:以容易理解的格式输出文件系统大小,例如124KB.345MB.46GB. 转自:https:// ...
- iOS 11 Xcode9开发 新特性学习 (新方法篇)
1 . 引入github (1) 在Xcode 9 中,引入了 gitHub,新源代码管理导航器 可以展示branch分支和 tag标签. (2)点进去,就可以看指定一次commit了哪些东西 2 ...
- 开发自己的composer package
参考:https://laravel-china.org/articles/6652/learn-to-develop-their-own-composer-package-and-to-use-pa ...
- cocos2d关于glew32.lib错误(转)
应项目需要使用cocos2d-x开发,又要学习新东东了.·cocos2d-x 是一个支持多平台的 2D 手机游戏引擎,用C++重写cocos2d-iphone引擎的一个开源项目,想了解更多的童鞋美去百 ...
- Python与硬件学习笔记:蜂鸣器(转)
相信大家对蜂鸣器都不会陌生,很多产品和方案中都会用到蜂鸣器,大部分都是使用蜂鸣器来做提示或报警,比如按键按下.开始工作.工作结束或是故障等等.这里对单片机在蜂鸣器驱动上的应用作一下描述. 蜂鸣器的介绍 ...
- 配置树莓派3和局域网NTP服务器实现内网时间校准
一.配置局域网NTP服务器 1.安装ntp-4.2.8p5-win32-setup.exe 下载地址:https://www.meinbergglobal.com/english/sw/ntp.htm ...
- FreeRtos堆栈检测应用
Free rtos每个任务都有自己的栈空间,每个任务需要的栈大小也是不同的.如果堆栈过小就会造成栈溢出,有时候栈溢出发生在某种特定顺序的任务切换中,比较难检测出.所以前期测试和监控任务栈用量就显得尤其 ...
- Docker容器技术-在开发中引用Docker
明确一点: 容器不适合构建那种发布周期以周或月为单位的大型单一架构企业软件,容器适合采用微服务的方式,以及探索诸如持续部署这样的技术,使得我们能安全地在一天内多次更新生产环境. 一.在开发中引用Doc ...
- Nginx配置指令的执行顺序
rewrite阶段 rewrite阶段是一个比较早的请求处理阶段,这个阶段的配置指令一般用来对当前请求进行各种修改(比如对URI和URL参数进行改写),或者创建并初始化一系列后续处理阶段可能需要的Ng ...
- 摊铺机基本参数介绍(三一重工SSP220C-5)
三一重工SSP220C-5稳定土摊铺机参数 SSP系列稳定土摊铺机SSP220C-5 动力强劲162kw 动力充分满足摊铺机各种工况下动力需求 高效任何工况,确保摊铺能力大于900t/h,行业内绝无仅 ...