zoukankan      html  css  js  c++  java
  • HTTP层 —— 中间件

     

    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 AppHttpMiddleware;
    
    use Closure;
    class CheckAge
    {
        /**
         * 返回请求过滤器
         *
         * @param IlluminateHttpRequest $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 AppHttpMiddleware;
    
    use Closure;
    
    class BeforeMiddleware
    {
        public function handle($request, Closure $next)
        {
            // 执行动作
    
            return $next($request);
        }
    }
    

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

    <?php
    
    namespace AppHttpMiddleware;
    
    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 AppHttpKernel Class...
    
    protected $routeMiddleware = [
        'auth' => IlluminateAuthMiddlewareAuthenticate::class,
        'auth.basic' => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class,
        'bindings' => IlluminateRoutingMiddlewareSubstituteBindings::class,
        'can' => IlluminateAuthMiddlewareAuthorize::class,
        'guest' => AppHttpMiddlewareRedirectIfAuthenticated::class,
        'throttle' => IlluminateRoutingMiddlewareThrottleRequests::class,
    ];
    

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

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

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

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

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

    use AppHttpMiddlewareCheckAge;
    
    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' => [
            AppHttpMiddlewareEncryptCookies::class,
            IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class,
            IlluminateSessionMiddlewareStartSession::class,
            IlluminateViewMiddlewareShareErrorsFromSession::class,
            AppHttpMiddlewareVerifyCsrfToken::class,
            IlluminateRoutingMiddlewareSubstituteBindings::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 AppHttpMiddleware;
    
    use Closure;
    class CheckRole
    {
        /**
         * 运行请求过滤器
         *
         * @param IlluminateHttpRequest $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 IlluminateSessionMiddleware;
    
    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 方法将该中间件注册到容器中。

  • 相关阅读:
    jQuery 基本选择器
    JavaScriptif while for switch流程控制 JS函数 内置对象
    JavaScrip基本语法
    数据库 存储引擎 表的操作 数值类型 时间类型 字符串类型 枚举集合 约束
    数据库基础知识 管理员 用户登录授权的操作
    粘包的产生原理 以及如何解决粘包问题
    socket TCP DPT 网络编程
    2018年年终总结
    Android技术分享
    No accelerator found
  • 原文地址:https://www.cnblogs.com/zhengyanbin2016/p/6005037.html
Copyright © 2011-2022 走看看