HTTP 中间件

未匹配的标注
本文档最新版为 6.x,旧版本可能放弃维护,推荐阅读最新版!

HTTP 中间件

介绍

HTTP 中间件提供一个方便的机制来过滤访问应用的请求,例如 Lumen 使用 Auth 中间件来验证用户的合法性,如果用户没有通过验证,该中间件会将用户重定向到登录页。反之, 中间件允许请求并进一步执行。

当然,除了身份验证,中间件还可以用来执行各种任务。 例如:CORS 中间件给所有返回的请求加上正确的头部,日志中间件会记录所有进入应用的请求。

所有的中间件都应放在 app/Http/Middleware 目录下。

创建中间件

为了正确的创建中间件,我们先复制 Lumen 自带的中间件示例 ExampleMiddleware 文件。在这个示例中,我们只允许参数 age 大于 200 时才能访问下一步,否则,会将用户重定向到 「home」这个表示首页的页面上。(PS:有点拦路求财的意思)

<?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

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 请求期间运行,只需要在 bootstrap/app.php 文件中的 $app->middleware() 方法中列出这个中间件类:

$app->middleware([
   App\Http\Middleware\OldMiddleware::class
]);

路由中间件

在路由中使用指定的中间件时,你需要在 bootstrap/app.php$app->routeMiddleware() 形式添加:

$app->routeMiddleware([
    'auth' => App\Http\Middleware\Authenticate::class,
]);

添加好中间件之后, 你可以在路由中添加以 middleware为键名,值为设定好的$app:

$router->get('admin/profile', ['middleware' => 'auth', function () {
    //
}]);

在路由中使用多个中间件:

$router->get('/', ['middleware' => ['first', 'second'], function () {
    //
}]);

多个路由使用同一个中间件:

$router->group(['middleware' => 'test'], function($router){
$router->get('login', 'LoginController@login');
$router->get('test', 'TestController@test');
});

中间件参数

中间件可以接收自定义参数。举个栗子?,如果你的应用程序需要校验某个用户角色是否具有某个操作的权限,你可以创建一个 RoleMiddleware 这么个中间件用来接收附加参数

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

<?php

namespace App\Http\Middleware;

use Closure;

class RoleMiddleware
{
    /**
     * 请求过滤.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string  $role
     * @return mixed
     */
    public function handle($request, Closure $next, $role)
    {
        if (! $request->user()->hasRole($role)) {
            // 跳转...
        }

        return $next($request);
    }

}

如何在路由中使用呢?可以在路由中使用 : 分割中间件名称和参数。多个参数应当使用逗号分隔开

$router->put('post/{id}', ['middleware' => 'role:editor', function ($id) {
    //
}]);

Terminable 中间件

一些时候我们希望中间件在 HTTP 响应被发送到浏览器后才运行。例如:「 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 方法必须同时接受请求和响应。一旦定义了 terminable 中间件,就应该把它添加到 bootstrap/app.php 文件中的全局中间件清单中。

当在中间件中调用 terminate 方法时,Lumen 将会从 服务容器 中解析一个全新的中间件实例。如果想在 handleterminate 方法被调用时使用一致的中间件实例,只需在容器中使用容器的 singleton 方法注册中间件。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/lumen/5.5/http-...

译文地址:https://learnku.com/docs/lumen/5.5/http-...

上一篇 下一篇
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
贡献者:8