溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Laravel異常處理類怎么進(jìn)行重寫

發(fā)布時(shí)間:2020-12-21 14:54:44 來源:億速云 閱讀:235 作者:Leah 欄目:開發(fā)技術(shù)

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)Laravel異常處理類怎么進(jìn)行重寫,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

首先我們在app/Exceptions目錄新建一個(gè)ExceptionHandler.php繼承自Handler.php

namespace App\Exceptions;


class ExceptionHandler extends Handler
{

}

然后我們在bootstrap/app.php中,使用我們自定義的異常處理類ExceptionHandler替換掉默認(rèn)的Handler類

//改為我們自定義的ExceptionHandler類
$app->singleton(
 Illuminate\Contracts\Debug\ExceptionHandler::class,
 App\Exceptions\ExceptionHandler::class
);

接下來我們就開始重寫渲染方法

在render方法里,我們根據(jù).env文件中的APP_DEBUG來判斷,如果是調(diào)試模式,我們還是按照默認(rèn)方式來渲染錯(cuò)誤,如果是非調(diào)試模式,我們就返回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()
 ]);
 }
}

這樣我們就可以根據(jù)APP_DEBUG的值設(shè)置是否返回JSON格式的數(shù)據(jù)了,現(xiàn)在我們把.env的APP_DEBUG的值設(shè)為false來測試一下,然后我們故意把代碼寫錯(cuò),通過postman或?yàn)g覽器來訪問接口

Route::get('/', function () {
 //這是一段缺少了分號的代碼,會(huì)報(bào)異常
 echo 'Hello World!'
});

Laravel異常處理類怎么進(jìn)行重寫

在APP_DEBUG=true的情況下還仍然是默認(rèn)渲染,方便我們查找錯(cuò)誤排錯(cuò)

異常類默認(rèn)會(huì)把異常以日志的形式記錄在storage/logs目錄下,并且以laravel-日期(YYYY-MM-DD)命名的形式,.log為后綴保存錯(cuò)誤日志

Laravel異常處理類怎么進(jìn)行重寫

我們打開這個(gè)日志文件查看記錄的錯(cuò)誤信息,我們可以發(fā)現(xiàn)錯(cuò)誤信息記錄的非常詳細(xì),除了錯(cuò)誤說明之外,還記錄了調(diào)用棧,如下圖所示

Laravel異常處理類怎么進(jìn)行重寫

基本上紅框里的信息就夠我們排錯(cuò)了,不需要像現(xiàn)在這樣記錄的這么詳細(xì),所以要想不記錄調(diào)用棧,我們可以重寫report方法

首先我們看一下框架的report方法,代碼在(src/Illuminate/Foundation/Exceptions/Handler.php),我用紅框框起來的代碼就是調(diào)用棧信息,我們在重寫這個(gè)方法時(shí)只需要完全拷貝這個(gè)方法里的所有代碼到我們自定義的report方法里,然后把紅框里的代碼去掉即可

Laravel異常處理類怎么進(jìn)行重寫

我們在我們自定義的異常處理類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()
 );
}

然后我們再重新請求一下接口再去查看錯(cuò)誤日志的記錄,可以發(fā)現(xiàn)確實(shí)沒有記錄調(diào)用棧信息了,但是下面的信息還是不夠,我們沒法根據(jù)下面的信息判斷錯(cuò)誤發(fā)生在哪一個(gè)文件和哪一行,如果能在記錄錯(cuò)誤信息的時(shí)候同時(shí)記錄發(fā)生錯(cuò)誤的文件和行就更好了,所以借著修改report方法

Laravel異常處理類怎么進(jìn)行重寫

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()方法加上了文件和行數(shù),保存代碼再次訪問接口,查看錯(cuò)誤日志文件我們可以看到發(fā)生錯(cuò)誤的文件和行數(shù)已經(jīng)記錄下來了,有了這些信息基本我們就可以找到錯(cuò)誤

Laravel異常處理類怎么進(jìn)行重寫

截止到這里實(shí)現(xiàn)最初的需求我們的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()
 );
 }
}

然后還不夠,我們發(fā)現(xiàn)剛剛我們把服務(wù)器端的錯(cuò)誤信息以JSON格式返回給客戶端了,這是不允許的,我們應(yīng)該只把一些客戶端錯(cuò)誤返回給客戶端,比如密碼不足六位、身份證不合法諸如此類,而服務(wù)端出現(xiàn)錯(cuò)誤時(shí)我們只返回給客戶端一個(gè)模糊的信息即可,比如“服務(wù)器錯(cuò)誤”,把真實(shí)的服務(wù)器錯(cuò)誤信息記錄在日志里面方便開發(fā)人員排查錯(cuò)誤

所以我們需要定義一個(gè)客戶端異常專門用戶返回客戶端錯(cuò)誤,使用如下命令在app/Exceptions目錄下生成一個(gè)ClientException.php文件

php artisan make:exception ClientException

修改為構(gòu)造方法為如下代碼

namespace App\Exceptions;

use Exception;

class ClientException extends Exception
{
 public function __construct($code, $msg)
 {
 parent::__construct($msg, $code);
 }
}

接著我們繼續(xù)修改ExceptionHandler.php

namespace App\Exceptions;


use Exception;
use Illuminate\Support\Reflector;
use Psr\Log\LoggerInterface;

class ExceptionHandler extends Handler
{
 /**
 * @var int 錯(cuò)誤碼
 */
 protected $code;
 /**
 * @var string 錯(cuò)誤信息
 */
 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 = '服務(wù)器錯(cuò)誤';
 }
 
 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屬性的異常類都不會(huì)被上報(bào),因?yàn)榭蛻舳隋e(cuò)誤信息我們不需要記錄,所以將其添加到$dontReport屬性里,并且在render方法里把異常大概分為了兩大類,一大類就是客戶端異常,另一大類就是服務(wù)器異常,我們把服務(wù)器異常統(tǒng)一code為500,錯(cuò)誤信息為服務(wù)器錯(cuò)誤,將真實(shí)的錯(cuò)誤信息記錄在了錯(cuò)誤日志里,避免把服務(wù)器信息暴露給了客戶端。

現(xiàn)在我們來測試我們重寫異常的結(jié)果

假如我們想返回客戶端異常,比如沒有權(quán)限,這類客戶端異常在錯(cuò)誤日志里都不會(huì)產(chǎn)生記錄,我們本身也不需要記錄

Route::get('/', function () {
 throw new \App\Exceptions\ClientException(403, '你沒有權(quán)限');
});

Laravel異常處理類怎么進(jìn)行重寫

對于服務(wù)器端的錯(cuò)誤,如少些了分號,客戶端就只會(huì)知道服務(wù)器的某個(gè)接口出了問題,但是不清楚具體問題是什么

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

Laravel異常處理類怎么進(jìn)行重寫

但是真實(shí)的錯(cuò)誤信息會(huì)記錄在錯(cuò)誤日志里,我們?nèi)耘f可以通過錯(cuò)誤日志來修改我們服務(wù)端的錯(cuò)誤

Laravel異常處理類怎么進(jìn)行重寫

上述就是小編為大家分享的Laravel異常處理類怎么進(jìn)行重寫了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI