Laravel 使用后置中间件

玩啦 2年多的 laravel 最近才注意到 laravel 的中间件还有后置的;
之前我理解的中间件都是在请求之前做的一些逻辑判断;
那么后置中间件可以做一些什么呢?
1:统计记录API的响应时间,请求参数和响应值;
2:后台的一些操作记录;
......等等;
有了后置中间件;
对于我们处理某些业务会方便许多;
其实很简单;
Laravel 的中间件有一个叫做 terminate 的方法;
如果我们在中间件里面加上了该方法;
那么在 Laravel 整个生命周期执行快要结束的时候;
Laravel 就会执行这个方法,方法结构如下:
注意 : 中间件必须存在与你应该将它添加到 app/Http/Kernel.php;
全局中间件中。

public function terminate($request, $response)
{
     //编写业务逻辑
}

那Laravel 具体是怎么实现的呢?
这个嘛;
还需要追溯到Laravel的根目录 public/index.php;
大概是60行左右;

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

$response->send(); //给浏览器响应数据

$kernel->terminate($request, $response); //调用后置中间件

然后会去调用Laravel底层代码;
调用最关键的一个方法api\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php 里面的terminateMiddleware() 方法;

/**
     * Call the terminate method on any terminable middleware.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Illuminate\Http\Response  $response
     * @return void
     */
    protected function terminateMiddleware($request, $response)
    {
        $middlewares = $this->app->shouldSkipMiddleware() ? [] : array_merge(
            $this->gatherRouteMiddleware($request),
            $this->middleware
        );

        foreach ($middlewares as $middleware) {
            if (! is_string($middleware)) {
                continue;
            }
            list($name) = $this->parseMiddleware($middleware);
            Log::info("中间件名称 =============== ",[$name]);
            $instance = $this->app->make($name);

            if (method_exists($instance, 'terminate')) {
                $instance->terminate($request, $response);
            }
        }
    }

我们直接上代码;
定义中间件如下;
注意: 中间件必须定义在全局中间件中;
重要的事情说三遍 (╥╯^╰╥);

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Log;

class AdminAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next){
        Log::info('经过了前置中间件');
        return $next($request);
    }

    /**
     * @param $request
     * @param $response
     * @
     */
    public function terminate($request, $response){
        // 编写业务逻辑
        Log::info('经过了后置中间件');
    }
}

然后我们执行一下代码;
查看日志;

[2019-10-20 19:45:44] local.INFO: 经过了前置中间件
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["App\\Http\\Middleware\\EncryptCookies"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["Illuminate\\Session\\Middleware\\StartSession"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["Illuminate\\View\\Middleware\\ShareErrorsFromSession"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["App\\Http\\Middleware\\VerifyCsrfToken"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["Illuminate\\Routing\\Middleware\\SubstituteBindings"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["App\\Http\\Middleware\\TrimStrings"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["App\\Http\\Middleware\\TrustProxies"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["App\\Http\\Middleware\\EnableCrossRequestMiddleware"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["App\\Http\\Middleware\\Cors"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["App\\Http\\Middleware\\TrimStrings"] 
[2019-10-20 19:45:45] local.INFO: 中间件名称 ===============  ["App\\Http\\Middleware\\AdminAuth"] //我们刚刚定义的中间件
[2019-10-20 19:45:45] local.INFO: 经过了后置中间件

最后会判断中间件类里面是否存在 terminate 方法;
存在执行方法里面的逻辑;
๑乛◡乛๑ 后置中间件的实现方式;
大概就是这样;
最后送上开胃小菜;
在某种情况下,你可能需要中间件以特定的顺序执行;
但是当它们被分配到路由时;
你无法控制它们的顺序。
在这种情况下,可以使用 app/Http/Kernel.php 文件的排序中间件;

/**
 * 中间件的优先级排序列表
 *
 * 将会强制非全局中间件始终保持给定的顺序。
 *
 * @var array
 */
protected $middlewarePriority = [
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \App\Http\Middleware\Authenticate::class,
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Auth\Middleware\Authorize::class,
];

app/Http/Kernel.php 的 $middlewarePriority 属性对应着 对应着 api\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php 的 $middlewarePriority 属性 ;
$middlewarePriority 属性指定中间件优先级
一一对应的;
这是意外收获;
加油哟

备注:
需要使用 laravel 内置的函数 response() 返回响应:

 /**
     * @param int $code
     * @param string $msg
     * @param string $data
     * @param bool $page
     * @return \Illuminate\Http\JsonResponse
     * @author shidatuo
     * @description 返回json数据
     */
    function jsonReturn($code = 0, $msg='', $data='', $page = false){
        if(empty($data))
            $data = [];
        if(!$page)
            return response()->json(compact('code','msg','data'));
        $rs  = ['code' => $code];
        $rs += ['msg'  => $msg];
        $rs += $data;
        return response()->json($rs);
    }

史大坨博客
请先登录后发表评论
  • 最新评论
  • 总共0条评论