跳转到帖子
  • 游客您好,欢迎来到黑客世界论坛!您可以在这里进行注册。

    赤队小组-代号1949(原CHT攻防小组)在这个瞬息万变的网络时代,我们保持初心,创造最好的社区来共同交流网络技术。您可以在论坛获取黑客攻防技巧与知识,您也可以加入我们的Telegram交流群 共同实时探讨交流。论坛禁止各种广告,请注册用户查看我们的使用与隐私策略,谢谢您的配合。小组成员可以获取论坛隐藏内容!

    TheHackerWorld官方

  • 0

重写Laravel异常处理类


HACK1949

问题

重写Laravel异常处理类

5fe8693633b1e.png

现在开发前后端别离变得越来越流行了,后端只提供接口回来json格局的数据,即使是过错信息也要以json格局来回来,但是现在无论是Laravel结构仍是ThinkPHP结构,都只提供了回来json数据的办法,对反常的处理并不是以json格局来回来给咱们,所以这儿就需要咱们自己来改写。

首先咱们在app/Exceptions目录新建一个ExceptionHandler.php承继自Handler.php

namespace App\Exceptions; class ExceptionHandler extends Handler {

}

然后咱们在bootstrap/app.php中,运用咱们自界说的反常处理类ExceptionHandler替换掉默认的Handler类

//改为咱们自界说的ExceptionHandler类 $app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\ExceptionHandler::class
);

接下来咱们就开端重写烘托办法

在render办法里,咱们依据.env文件中的APP_DEBUG来判别,如果是调试形式,咱们仍是按照默认办法来烘托过错,如果是非调试形式,咱们就回来JSON格局的信息

namespace App\Exceptions; use Exception; class ExceptionHandler extends Handler { public function render($request, Exception $exception) { if (env('APP_DEBUG')) { return parent::render($request, $exception);
        } return response()->json([ 'code' => $exception->getCode(), 'msg' => $exception->getMessage()
        ]);
    }
}

这样咱们就能够依据APP_DEBUG的值设置是否回来JSON格局的数据了,现在咱们把.env的APP_DEBUG的值设为false来测验一下,然后咱们故意把代码写错,经过postman或浏览器来拜访接口

Route::get('/', function () { //这是一段缺少了分号的代码,会报反常 echo 'Hello World!' });

720430-20201218095457353-286909359.png

在APP_DEBUG=true的情况下还仍然是默认烘托,便利咱们查找过错排错

反常类默认会把反常以日志的形式记载在storage/logs目录下,而且以laravel-日期(YYYY-MM-DD)命名的形式,.log为后缀保存过错日志

720430-20201218100921976-1779191320.png

咱们翻开这个日志文件检查记载的过错信息,咱们能够发现过错信息记载的十分详细,除了过错说明之外,还记载了调用栈,如下图所示

720430-20201218100932511-36549864.png

基本上红框里的信息就够咱们排错了,不需要像现在这样记载的这么详细,所以要想不记载调用栈,咱们能够重写report办法

首先咱们看一下结构的report办法,代码在(src/Illuminate/Foundation/Exceptions/Handler.php),我用红框框起来的代码便是调用栈信息,咱们在重写这个办法时只需要彻底复制这个办法里的所有代码到咱们自界说的report办法里,然后把红框里的代码去掉即可

720430-20201218100947671-1672363008.png

咱们在咱们自界说的反常处理类ExceptionHandler.php中重写report办法

public function report(Exception $exception) { if ($this->shouldntReport($exception)) { return;
    } if (Reflector::isCallable($reportCallable = [$exception, 'report'])) { return $this->container->call($reportCallable);
    } try {
        $logger = $this->container->make(LoggerInterface::class);
    } catch (Exception $ex) { throw $exception;
    }

    $logger->error(
        $exception->getMessage()
    );
}

然后咱们再重新恳求一下接口再去检查过错日志的记载,能够发现的确没有记载调用栈信息了,但是下面的信息仍是不行,咱们无法依据下面的信息判别过错发生在哪一个文件和哪一行,如果能在记载过错信息的时候一起记载发生过错的文件和行就更好了,所以借着修改report办法

720430-20201218100959943-131320049.png

public function report(Exception $exception) { if ($this->shouldntReport($exception)) { return;
    } if (Reflector::isCallable($reportCallable = [$exception, 'report'])) { return $this->container->call($reportCallable);
    } try {
        $logger = $this->container->make(LoggerInterface::class);
    } catch (Exception $ex) { throw $exception;
    }

    $logger->error(
        $exception->getMessage()." at ".$exception->getFile().":".$exception->getLine()
    );
}

在代码里我经过exception的getFile()、getLine()办法加上了文件和行数,保存代码再次拜访接口,检查过错日志文件咱们能够看到发生过错的文件和行数现已记载下来了,有了这些信息基本咱们就能够找到过错

720430-20201218101009160-1561299257.png

截止到这儿完成开始的需求咱们的ExceptionHandler.php只需要有这些代码

namespace App\Exceptions; use Exception; use Illuminate\Support\Reflector; use Psr\Log\LoggerInterface; class ExceptionHandler extends Handler { public function render($request, Exception $exception) { if (env('APP_DEBUG')) { return parent::render($request, $exception);
        } return response()->json([ 'code' => $exception->getCode(), 'msg' => $exception->getMessage()
        ]);
    } public function report(Exception $exception) { if ($this->shouldntReport($exception)) { return;
        } if (Reflector::isCallable($reportCallable = [$exception, 'report'])) { return $this->container->call($reportCallable);
        } try {
            $logger = $this->container->make(LoggerInterface::class);
        } catch (Exception $ex) { throw $exception;
        }

        $logger->error(
            $exception->getMessage()." at ".$exception->getFile().":".$exception->getLine()
        );
    }
}

然后还不行,咱们发现刚刚咱们把服务器端的过错信息以JSON格局回来给客户端了,这是不允许的,咱们应该只把一些客户端过错回来给客户端,比方暗码不足六位、身份证不合法诸如此类,而服务端呈现过错时咱们只回来给客户端一个模糊的信息即可,比方“服务器过错”,把实在的服务器过错信息记载在日志里面便利开发人员排查过错

所以咱们需要界说一个客户端反常专门用户回来客户端过错,运用如下命令在app/Exceptions目录下生成一个ClientException.php文件

php artisan make:exception ClientException

修改为构造办法为如下代码

namespace App\Exceptions; use Exception; class ClientException extends Exception { public function __construct($code, $msg) { parent::__construct($msg, $code);
    }
}

接着咱们继续修改ExceptionHandler.php

namespace App\Exceptions; use Exception; use Illuminate\Support\Reflector; use Psr\Log\LoggerInterface; class ExceptionHandler extends Handler { /**
     * @var int 过错码
     */ protected $code; /**
     * @var string 过错信息
     */ protected $message; protected $dontReport = [
        ClientException::class
    ]; public function render($request, Exception $exception) { if ($exception instanceof ClientException) { $this->code = $exception->getCode(); $this->message = $exception->getMessage();
        } else { if (env('APP_DEBUG')) { return parent::render($request, $exception);
            } $this->code = 500; $this->message = '服务器过错';
        } return response()->json([ 'code' => $this->code, 'msg' => $this->message
        ]);
    } public function report(Exception $exception) { if ($this->shouldntReport($exception)) { return;
        } if (Reflector::isCallable($reportCallable = [$exception, 'report'])) { return $this->container->call($reportCallable);
        } try {
            $logger = $this->container->make(LoggerInterface::class);
        } catch (Exception $ex) { throw $exception;
        }

        $logger->error(
            $exception->getMessage()." at ".$exception->getFile().":".$exception->getLine()
        );
    }
}

关于上面的修改做一下说明,laravel的$dontReport特点的反常类都不会被上报,因为客户端过错信息咱们不需要记载,所以将其添加到$dontReport特点里,而且在render办法里把反常大概分为了两大类,一大类便是客户端反常,另一大类便是服务器反常,咱们把服务器反常一致code为500,过错信息为服务器过错,将实在的过错信息记载在了过错日志里,避免把服务器信息露出给了客户端。

现在咱们来测验咱们重写反常的结果

假设咱们想回来客户端反常,比方没有权限,这类客户端反常在过错日志里都不会发生记载,咱们自身也不需要记载

Route::get('/', function () { throw new \App\Exceptions\ClientException(403, '你没有权限');
});

720430-20201218101025893-1667580701.png

关于服务器端的过错,如少些了分号,客户端就只会知道服务器的某个接口出了问题,但是不清楚具体问题是什么

Route::get('/', function () { echo 'Hello World!' });

720430-20201218101040992-351437292.png

但是实在的过错信息会记载在过错日志里,咱们依旧能够经过过错日志来修改咱们服务端的过错

720430-20201218101049309-437413089.png

咱们还能够在render办法中参加告警代码,如果是服务端过错就给管理员发送邮件。

至此,咱们的重写Laravel反常处理类就算完成啦,期望对正在准备运用Laravel做前后端别离项目的你有所协助。

链接帖子
意见的链接
分享到其他网站

这个问题有0个答案

推荐的帖子

此问题没有答案

黑客攻防讨论组

黑客攻防讨论组

    You don't have permission to chat.
    • 最近浏览   0位会员

      • 没有会员查看此页面。
    ×
    ×
    • 创建新的...