简介
HTTP 中间件提供了为过滤进入应用的 HTTP 请求提供了一套便利的机制。例如,Laravel 内置了一个中间件来验证用户是否通过受权,若是用户没有通过受权,中间件会将用户重定向到登陆页面,不然若是用户通过受权,中间件就会容许请求继续往前进入下一步操做。php
固然,除了认证以外,中间件还能够被用来处理更多其它任务。好比:CORS 中间件能够用于为离开站点的响应添加合适的头(跨域);日志中间件能够记录全部进入站点的请求。laravel
Laravel框架自带了一些中间件,包括维护模式、认证、CSRF 保护中间件等等。全部的中间件都位于 app/Http/Middleware 目录。web
定义中间件
要建立一个新的中间件,能够经过 Artisan 命令 make:middleware:api
php artisan make:middleware Test
这个命令会在 app/Http/Middleware 目录下建立一个新的中间件类 Test跨域
<?php
namespace App\Http\Middleware;
use Closure;
class Test
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
return $next($request);
}
}
程序执行前调用的方法数组
public function handle($request, Closure $next, $guard = null)
{
// 执行动做
if(!$request->session()->has('user')){
return redirect("login");
}
return $next($request);
}
程序执行后调用的方法浏览器
public function handle($request, Closure $next)
{
$response = $next($request);
// 执行动做
if(!$request->session()->has('huser')){
return redirect("login/index");
}
return $response;
}
全局中间件session
若是你想要中间件在每个 HTTP 请求期间被执行,只须要将相应的中间件类设置到 app/Http/Kernel.php 的数组属性 $middleware 中便可。app
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
分配中间件到路由框架
若是你想要分配中间件到指定路由,首先应该在 app/Http/Kernel.php 文件中分配给该中间件一个简写的 key,默认状况下,该类的 $routeMiddleware 属性包含了 Laravel 内置的入口中间件,添加你本身的中间件只须要将其追加到后面并为其分配一个 key:
在 App\Http\Kernel 里中,添加一行'Test' => \App\Http\Middleware\Test::class,
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'Test' => \App\Http\Middleware\Test::class,
];
中间件在 HTTP Kernel 中被定义后,可使用 middleware 方法链的方式定义路由:
Route::any('test','IndexController@test')->middleware('Test')
中间件组(分组)
有时候你可能想要经过指定一个键名的方式将相关中间件分到一个组里面,从而更方便将其分配到路由中,这能够经过使用 HTTP Kernel 的 $middlewareGroups 实现。
Laravel 自带了开箱即用的 web 和 api 两个中间件组以包含能够应用到 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\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
'Test'=>[
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\Test::class,
]
];
中间件组能够被分配给路由和控制器动做,使用和单个中间件分配一样的语法。再次申明,中间件组的目的只是让一次分配给路由多个中间件的实现更加简单
Route::group(['middleware' => ['Test']], function() {
Route::get('/', 'IndexController@index');
Route::any('test','IndexController@test');
});
可终止的中间件
有时候中间件可能须要在 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 将会从服务容器中取出该中间件的新的实例,若是你想要在调用 handle 和 terminate 方法时使用同一个中间件实例,则须要使用容器的 singleton 方法将该中间件注册到容器中。
laravel框架中构造方法中调用sessionpublic function __construct(){ $this->middleware(function ($request, $next) { $user_data = $request->session() -> get('user_data'); if(empty($user_data)) { redirect('/login')->send(); } return $next($request); }); }