Skip to content

HTTP 中间件

介绍

HTTP 中间件为过滤进入应用程序的 HTTP 请求提供了一种方便的机制。例如,Laravel 包含一个中间件,用于验证应用程序的用户是否已认证。如果用户未认证,中间件会将用户重定向到登录页面。然而,如果用户已认证,中间件将允许请求进一步进入应用程序。

当然,中间件可以编写以执行除认证之外的各种任务。CORS 中间件可能负责为离开应用程序的所有响应添加适当的头信息。日志中间件可能会记录所有进入应用程序的请求。

Laravel 框架中包含了几种中间件,包括用于维护、认证、CSRF 保护等的中间件。所有这些中间件都位于 app/Http/Middleware 目录中。

定义中间件

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

php
php artisan make:middleware OldMiddleware

此命令将在 app/Http/Middleware 目录中放置一个新的 OldMiddleware 类。在这个中间件中,我们将仅允许访问路由,如果提供的 age 大于 200。否则,我们将用户重定向回 "home" URI。

php
<?php namespace App\Http\Middleware;

use Closure;

class OldMiddleware {

	/**
	 * 运行请求过滤器。
	 *
	 * @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 重定向给客户端;否则,请求将被传递到应用程序的更深层。要将请求传递到应用程序的更深层(允许中间件“通过”),只需使用 $request 调用 $next 回调。

最好将中间件设想为 HTTP 请求在到达应用程序之前必须通过的一系列“层”。每一层都可以检查请求,甚至完全拒绝它。

/ 中间件

中间件是在请求之前还是之后运行,取决于中间件本身。这个中间件将在请求被应用程序处理之前执行某些任务:

php
<?php namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware implements Middleware {

	public function handle($request, Closure $next)
	{
		// 执行操作

		return $next($request);
	}
}

然而,这个中间件将在请求被应用程序处理之后执行其任务:

php
<?php namespace App\Http\Middleware;

use Closure;

class AfterMiddleware implements Middleware {

	public function handle($request, Closure $next)
	{
		$response = $next($request);

		// 执行操作

		return $response;
	}
}

注册中间件

全局中间件

如果希望在每个 HTTP 请求期间运行中间件,只需在 app/Http/Kernel.php 类的 $middleware 属性中列出中间件类。

将中间件分配给路由

如果希望将中间件分配给特定路由,首先应在 app/Http/Kernel.php 文件中为中间件分配一个简写键。默认情况下,此类的 $routeMiddleware 属性包含 Laravel 附带的中间件条目。要添加自己的中间件,只需将其附加到此列表并为其分配一个你选择的键。

一旦在 HTTP 内核中定义了中间件,就可以在路由选项数组中使用 middleware 键:

php
Route::get('admin/profile', ['middleware' => 'auth', function()
{
	//
}]);

可终止中间件

有时,中间件可能需要在 HTTP 响应已发送到浏览器之后执行一些工作。例如,Laravel 附带的“会话”中间件在响应发送到浏览器之后将会话数据写入存储。要实现这一点,可以将中间件定义为“可终止”的。

php
use Closure;
use Illuminate\Contracts\Routing\TerminableMiddleware;

class StartSession implements TerminableMiddleware {

	public function handle($request, Closure $next)
	{
		return $next($request);
	}

	public function terminate($request, $response)
	{
		// 存储会话数据...
	}

}

如你所见,除了定义 handle 方法外,TerminableMiddleware 还定义了一个 terminate 方法。此方法接收请求和响应。一旦定义了可终止中间件,应将其添加到 HTTP 内核中的全局中间件列表中。