如何从laravel8 自定义异常处理类的坑中爬出来;新问题:原理是啥?如何自定义日志格式?

异常处理类的问题解决了,但又抛出了新的问题:1.我解决问题的原理是啥?2.如何自定义日志格式?

自定义异常处理类经常捕捉不到错误,直接显示Error基类错误,我找到解决办法,但具体原理我不懂,希望有大神指点,我补一下解决方案:

希望高手来讲讲原理!感谢

新问题是:自定义的异常类,经常不能被laravel 异常处理类 handler捕捉到,有时可以有时不可以,有时删除缓存就好了,我建议如我小白看看这是一个坑没发生也看看:

回到家,我以为可能公司电脑不好,我又在自家Windows试了试还是一样,然后在Linux虚拟机上,结果依然。
我在捋一下我想要做的:我希望,服务端的异常,比如代码错误,或者未发现的逻辑错误,响应结果只显示简单的代号,但是记录日志(怎么记录自定义格式又是一个问题~),而用户端由于操作失误导致的异常,显示详细一点,但没有要记录。

上代码:异常处理类:需要看我的注释哟~

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;

class Handler extends ExceptionHandler
{
    protected $dontReport = [
    ];

    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];
    public function register()
    {
    }
    public function render($request,Throwable $e)
    {
    //为什么这么写? 所有客户端的异常都继承BaseException
    // 为什么不用instanceof 因为我担心 所有异常的基类都是Exception
    //具体我就没测试但是这样好用~
        if(get_parent_class(get_class($e)) == "App\\Exceptions\\BaseException")//, $e->getSt()
        {
            return response()->json(['code' => $e->getCode(), 'msg' => $e->getMessage(),'me'=>get_class($e)]);
        }else{
            //如果是服务器的异常在这里显示
            //如果不是测试环境就显示就不显示详细信息
            //如果是测试环境就显示详细信息
             if (env('APP_DEBUG')) {
                return parent::render($request, $exception);
            }
            return response()->json([
                'status' => 500,
                'message' => '服务器错误',
                'me'=> get_class($e),//这里是测试用滴忽略哈
                'father'=>get_parent_class(get_class($e))
            ],500);
        //    return parent::render($request,$e);
        }
    }

}

问题其实不是出现在这里,问题出现在下面的自定义异常类:看注释~

<?php

namespace App\Exceptions;

use Exception;

class BaseException extends Exception
{
//    protected  $status ;
   public function __construct($code, $msg)
   {
       //属性还是得写滴
       $this->code = $code;
       $this->message = $msg;
       //问题出现在这里,这里不能调用父类方法,不然就会出现问题
       //比如handler捕捉不到,一直报Error 错误而不是我们自定义的错误
    //    parent::__construct($code, $msg);
   }

}

先把如何报错的代码拿出来:还是看注释~

use Illuminate\Support\Facades\Route;

Route::get('/abc', function () {
    //这是一段缺少了分号的代码,会报服务端的错误,被动犯错~
    echo "123"
//下面是主动犯错,也就是客户端的异常~
//    throw new \App\Exceptions\UserException(404, '你没有权限啊',200);
});

少分号postman:

如何从laravel8 自定义异常处理类的坑中爬出来;新问题:原理是啥?如何自定义日志格式?

主动抛出UserException:

如何从laravel8 自定义异常处理类的坑中爬出来;新问题:原理是啥?如何自定义日志格式?

总结:laravel8 如果想和之前laravel5.6-laravel6一样,重写异常处理类,且和我一样分层,异常类中就得将构造方法重写,且不能调用父类的构造方法。

原文从这里开始 laravel8如何用laravel5.8的方法自定义异常处理类:

最近看了一天文章:

重写laravel8异常类


不知道能不能引用外站的贴子,如果不让我就删除。
我依然在测试,找到了一种解决办法:方法极为不推荐!只是希望大神给出优质答案!看到我个人也在努力~
代码位于app/exception/Handler

public function render($request,Throwable $e)
    {

//       $response = parent::render($request,$e);
        //假设客户端的一种异常是:那么返回异常
        if (get_class($e) == "App\\Exceptions\\BaseException") {
            return response()->json(['code' => $e->getCode(), 'msg' => $e->getMessage(),'a'=>get_class($e)], 200);
        }
        //不是客户端的那就是服务器端的:不把具体问题告知客户
        return response()->json([
            'status' => 500,
            'message' => '服务器错误',
        ],500);

    }

说明:

  • 我在register方法中使用renderable的闭包依然会被Handler下render覆盖;按理说这与上面的方法没什么区别,不好用可能是缓存问题。
  • 最后测试还是不好用,但是发现如果每次都把session 缓存删除上面的代码就好用了,所以放进renderable的闭包里不一定不好用。
  • 好吧,不推荐是因为不能用instanceof 所以之后客户端的其他异常类都得继续写 if …
  • 另一个问题是捕获,当抛出异常时,不是每次都能捕获到exception,而是直接报出来Error,不能每次都捕获成功是为什么?

跪求大神给出解答!

————————————————————分割线———————————————————

先说测试结果:laravel8的异常处理器Handel里的render会覆盖自定义异常类中的render

以下是详细经过,答题的时候说有详细的环境描述更好,希望我不是啰嗦。

在写api接口时,我想自定义异常类,特别是将服务器自身的问题写入日志,客服端只能看到错误码,而如果是客户操作出现的异常,正常响应给客户。
我百度到了上方连接的文章,正好能解决问题,但结果内发现了laravel5与laravel8的不同:
laravel5:
laravel8 如何自定义异常处理类?
laravel8:
laravel8 如何自定义异常处理类?

手册里说道自定义异常类可以直接写render

laravel8 如何自定义异常处理类?如何理解Throwable 类?

我也模仿定义了一个异常类:

laravel8 如何自定义异常处理类?
在路由中抛出:

laravel8 如何自定义异常处理类?
补充:另一种方式

laravel8 如何自定义异常处理类?
都能正常响应json数据

laravel8 如何自定义异常处理类?

但这并不是我想要的,我希望客户端的错误与服务器端的分开;

这里我就猜想在自定义异常类中使用自己的render,服务器报错则使用异常处理器handler里的render。

但结果是:异常处理器Handel里的render会覆盖自定义异常类中的render

有大神可以帮忙解答下么?我是真心努力了,百度了,也尽可能的测试了,我愿意付费,我不是有钱人,但真的想学好这本技术,工作上也正好能用上,就算付费也愿意分享大神的解决方法。价格不离谱就行~非常感谢!

《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 7

直接在Handle里面判断异常类型即可。if (客户端异常) xxxx。 if (服务端异常) xxxx

Laravel

1个月前 评论
wkcanfly (楼主) 1个月前
di-gua (作者) 1个月前
wkcanfly (楼主) 1个月前
wkcanfly (楼主) 1个月前
wkcanfly (楼主) 1个月前

谢谢您的回复!真心感谢!

1个月前 评论

不明白什么是客户端的错误与服务器端的错误分开。

  • Throwable类是所有异常与错误都需要实现的接口。Throwable你可以理解成是PHP中的所有错误。
  • 我的做法就是在 Handler类中接管render。写一个类 instanceof 异常 如果没有捕捉到就是用父级render处理,伪代码如下
public function render($request, Throwable $e)
{
     return app(ExceptionHandlerFactory::class)
         ->dispatch($e) ?? parent::render($request, $e)
}

class ExceptionHandlerFactory
{
    public function __construct(
        protected ApiResponse $response
    )
    {
    }

    public function dispatch(\Throwable $exception): ?JsonResponse
    {
         $rules = [
             ValidationException::class => $this->response->customize($exception->getCode(), [], $exception->getMessage()),
         ];

        foreach ($handles as $className => $handle) {
            if ($exception instanceof $className) {
                return $handle;
            }
        }
        return null;
    }
}
1个月前 评论
wkcanfly (楼主) 1个月前

@wkcanfly

日志具体查阅日志文档。如果还是不明白就去看monolog的文档。

我不明白你说的原理是什么。如果你指的是为什么laravel可以接管错误处理,那具体查阅 Illuminate\Foundation\Bootstrap\HandleExceptions 这个类。

原理是 通过 set_error_handler 、 set_exception_handler 、register_shutdown_function这几个函数接管了PHP错误处理

1个月前 评论
wkcanfly (楼主) 1个月前

是啥原理,能了解一下吗?

1周前 评论

laravel,应该是会自己判断是否返回json格式的错误

2天前 评论

laravel 的日志用的 monolog,配置应该差不多,在 config/logging.php 中,简单来说,我用过的如下:tap 可以用来给日志中增加额外的数据,formatter 可以修改日志格式,比如我就改为了 json 格式,方面后续的日志采集,

1天前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!