快速定位無用路由 媽媽再也不用擔心人工排雷了

Remember發表於2019-10-27

快速定位無用路由 再也不用人工排雷了

:hourglass:介紹

看到 Github 一個包,跟蹤路由的請求,記錄哪個路由在哪一個時刻被呼叫。這個包最大的目的不是分析資料,而是可以隨時隨地的檢視哪些路由沒被呼叫卻還存在程式中。比如你現在去了新的公司,接手了一個新的專案或者你一年前的專案,可能很多路由在前端的請求已經砍掉了,但是你後端的介面還沒去掉,這時候這個包的作用就發揮出來了,避免了你人工掃雷。

:hourglass:快速上手

確保 PHP 版本7.1及以上, Laravel 版本5.8及以上

composer require julienbourdeau/route-usage

接下來你所有的請求將記錄表中,你可以通過兩種方式來檢視路由情況,可以直接訪問 Auth.php

快速定位無用路由 再也不用人工排雷了

當然該擴充套件還提供了命令列檢視

快速定位無用路由 再也不用人工排雷了

加一個引數

快速定位無用路由 再也不用人工排雷了

剩下的好像也沒做什麼了,閒著也是閒著,看看他咋麼寫的

    public function boot()
    {
        Event::listen(RequestHandled::class, LogRouteUsage::class);

        $this->loadViewsFrom(__DIR__.'/../resources/views', 'route-usage');
        $this->loadMigrationsFrom(__DIR__.'/../database/migrations');
        $this->loadRoutesFrom(__DIR__.'/routes.php');

        if ($this->app->runningInConsole()) {
            // Registering package commands.
            $this->commands([
                UsageRouteCommand::class,
            ]);
        }
    }

引導應用程式執行服務,監聽 RequestHandled 事件,這個事件是在什麼時候執行的

#index.php
...
....
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);\
$response = $kernel->handle(\
    $request = Illuminate\Http\Request::capture()\
);

#Illuminate\Foundation\Http\Kernel

public function handle($request)
{
    .....
    .....
    ....
    $this->app['events']->dispatch(
        new Events\RequestHandled($request, $response)\
    );
  .....
}

進去看下監聽器具體幹了什麼,好吧說白了就是記錄2xx和3xx的請求記錄

    public function handle($event)
    {
        $status_code = $event->response->getStatusCode();

        if ($status_code > 400 || $status_code < 200) {
            return;
        }

        $method = $event->request->getMethod();
        $path = $event->request->route()->uri ?? $event->request->getPathInfo();
        $action = optional($event->request->route())->getAction()['uses'];

        if ($action instanceof \Closure) {
            $action = '[Closure]';
        } elseif (!is_string($action) && !is_null($action)) {
            $action = '[Unsupported]';
        }

        $identifier = sha1($method.$path.$action.$status_code);
        $date = date('Y-m-d H:i:s');

        DB::statement(
            "INSERT INTO route_usage
                    (`identifier`, `method`, `path`, `status_code`, `action`, `created_at`, `updated_at`)
                VALUES (?, ?, ?, ?, ?, ?, ?)
                ON DUPLICATE KEY UPDATE `updated_at` = '{$date}'",
            [$identifier, $method, $path, $status_code, $action, $date, $date]
        );
    }

接下來看監聽後面一坨是什麼

.....
......
  $this->loadViewsFrom(__DIR__.'/../resources/views', 'route-usage');
        $this->loadMigrationsFrom(__DIR__.'/../database/migrations');
        $this->loadRoutesFrom(__DIR__.'/routes.php');

        if ($this->app->runningInConsole()) {
            // Registering package commands.
            $this->commands([
                UsageRouteCommand::class,
            ]);
        }

如果應用中包含了路由,檢視還有遷移檔案,你需要告訴服務容器咋麼去載入他們,也就是位置甩給他們,如果是在命令列操作,需要把擴充套件包中的命令註冊到 Laravel中, 呼叫 commands ,檔案裡面就是一個繼承自 Illuminate\Foundation\Console\RouteListCommand 的基類

<?php

namespace Julienbourdeau\RouteUsage\Console\Commands;

use Illuminate\Foundation\Console\RouteListCommand;
use Julienbourdeau\RouteUsage\RouteUsage;

class UsageRouteCommand extends RouteListCommand
{
    protected $name = 'usage:route';

    protected $description = 'Show route list with the last access datetime';

    protected $headers = ['Domain', 'Method', 'URI', 'Last used', 'Name', 'Action', 'Middleware'];

    protected $compactColumns = ['method', 'uri', 'last used', 'action'];

    protected function getRoutes()
    {
        $routes = $this->splitRoutesByMethods(parent::getRoutes());

        // TODO: sort by updated_at and group by method+path
        $routeUsage = RouteUsage::all()->mapWithKeys(function ($r) {
            $key = $r->method.'.'.$r->path;

            return [$key => $r];
        });

        return $routes->map(function ($route) use ($routeUsage) {
            $usageKey = $route['method'].'.'.$route['uri'];
            $lastUsed = $routeUsage->has($usageKey) ?
                $routeUsage->get($usageKey)->updated_at->diffForHumans()
                : 'Never';

            return $this->option('compact') ?
                [
                    'method' => $route['method'],
                    'uri' => $route['uri'],
                    'last used' => $lastUsed,
                    'action' => $route['action'],
                ] : [
                    'domain' => $route['domain'],
                    'method' => $route['method'],
                    'uri' => $route['uri'],
                    'last used' => $lastUsed,
                    'name' => $route['name'],
                    'action' => $route['action'],
                    'middleware' => $route['middleware'],
                ];
        })->toArray();
    }

    protected function splitRoutesByMethods(array $routes)
    {
        return collect($routes)->transform(function ($r) {
            $splitRoutes = [];
            foreach (explode('|', $r['method']) as $m) {
                $r['method'] = $m;
                $splitRoutes[] = $r;
            }

            return $splitRoutes;
        })->flatten(1)->reject(function ($r) {
            return 'HEAD' === $r['method'];
        })->values();
    }
}

吳親庫裡

相關文章