TP6异常自定义捕捉和消息告警

浏览:7242 发布日期:2020/05/25 分类:技术分享 关键字: 异常处理 自定义 Exception
使用tp6 自定义异常处理,将404、500等错误进行处理
render渲染方法重写:
1、如果是ajax请求,则返回对应状态,调试模式下返回堆栈
2、如果是页面请求,则返回对应错误模板页面渲染。

report报告方法重写:
1、Undefined index、offset、variable比较常见,屏蔽以不推送消息,采用原生记录即可
2、推送消息走异步,防止并发出现响应变慢。记录异常的前几个堆栈的参数,方便开发验证问题
3、推送异常,走默认原生记录,防止死循环<?php
/*
 * @Description: 应用异常处理类
 * @Author: KingFer
 * @Date: 2019-08-13 17:24:45
 */ 

namespace app;

use app\common\helper\QueueHelper;
use ErrorException;
use Exception;
use InvalidArgumentException;
use ParseError;
use PDOException;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\ClassNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\RouteNotFoundException;
use think\exception\ValidateException;
use think\Response;
use Throwable;
use TypeError;

class ExceptionHandle extends Handle
{
    /**
     * 不需要记录信息(日志)的异常类列表
     * @var array
     */
    protected $ignoreReport = [
        HttpResponseException::class,
        ValidateException::class,
    ];

    protected $error_num;
    public function __construct()
    {
        $this->error_num = 'Y' . makeRandCode(13) . date('mdHis');
        parent::__construct(app());
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @access public
     * @param \think\Request   $request
     * @param Throwable $e
     * @return Response
     */
    public function render($request, Throwable $e): Response
    {
        if (!$this->isIgnoreReport($e)) {
            // 添加自定义异常处理机制
            // 参数验证错误
            if ($e instanceof ValidateException) {
                return json($e->getError(), 422);
            }

            // ajax请求404异常 , 不返回错误页面
            if (($e instanceof ClassNotFoundException || $e instanceof RouteNotFoundException) && request()->isAjax()) {
                return json(['msg' => env('app_debug') ? $e->getMessage() : '当前请求资源不存在,请稍后再试', 'code' => 404, 'data' => []]);
            }

            //类未找到, 返回错误页面
            if (($e instanceof ClassNotFoundException || $e instanceof RouteNotFoundException) || ($e instanceof HttpException && $e->getStatusCode() == 404)) {
                return view(root_path() . 'public/error/404.html', ['e' => $e], 404);
            }

            // ajax请求500异常, 不返回错误页面
            if (($e instanceof Exception || $e instanceof PDOException || $e instanceof HttpException || $e instanceof InvalidArgumentException || $e instanceof ErrorException || $e instanceof ParseError || $e instanceof TypeError) && request()->isAjax()) {
                return json(['msg' => env('app_debug') ? $e->getMessage() : '系统异常,请稍后再试', 'code' => 500, 'data' => env('app_debug') ? $e->getTrace() : []]);
            }

            // 内部异常 , 返回错误页面
            if ($e instanceof Exception || $e instanceof PDOException || $e instanceof InvalidArgumentException || $e instanceof ErrorException || $e instanceof ParseError || $e instanceof TypeError || ($e instanceof HttpException && $e->getStatusCode() == 500)) {
                return view(root_path() . 'public/error/500-2.html', ['e' => $e, 'error_num' => $this->error_num], 500);
            }
        }
        // 其他错误交给系统处理
        return parent::render($request, $e);
    }

    /**
     * 记录异常信息(包括日志或者其它方式记录)
     *
     * @access public
     * @param  Throwable $exception
     * @return void
     */
    public function report(Throwable $e): void
    {
        if (!$this->isIgnoreReport($e)) {
            if (
                $e instanceof ClassNotFoundException  || ($e instanceof HttpException && $e->getStatusCode() == 404)
                || stripos($e->getMessage(), "Undefined index:") !== false
                || stripos($e->getMessage(), "Undefined offset:") !== false
                || stripos($e->getMessage(), "Undefined variable:") !== false
            ) {
                //这是由Mongo日志记录抛出的异常 , 不能再把异常推进队列中, 否则会造成死循环
                //这里用原生report方法 , 防止死循环
                //类不存在的也不记录mongo日志
                //变量未定义 , 也不记录mongo日志
                parent::report($e);
                return;
            }
            try {

                //取出异常的部分堆栈参数,方便排查问题
                $args = $e->getTrace();
                $error_args = array_slice($args, 0, 5);
                foreach ($error_args as $k => $error) {
                    if (!isset($error['file'])) {
                        unset($error_args[$k]);
                    } else if (isset($error['file']) && (stripos($error['file'], 'thinkphp') || stripos($error['file'], 'index.php'))) {
                        unset($error_args[$k]);
                    }
                }
                //异常信息丢到队列处理
                QueueHelper::pushQueue("app\job\LogErrorMsg", "log_error_msg", [
                    'msg_type' => 'exception',
                    'system' => env('system_name'),
                    'error_num' => $this->error_num,
                    'error_handle' => [
                        'file' => $e->getFile(),
                        'line' => $e->getLine(),
                        'msg' => $e->getMessage(),
                        'trace' => $e->getTraceAsString(),
                        'trace_args' => $error_args,
                    ],

                ]);
                return;
            } catch (\ErrorException $error) {

                //入队异常 , 用原生report方法 , 防止死循环
                parent::report($e);
                return;
            } catch (\Exception $error) {

                //入队异常 , 用原生report方法 , 防止死循环
                parent::report($e);
                return;
            }
            // 使用内置的方式记录异常日志
            parent::report($e);
            return;
        }
    }
}
最佳答案
评论( 相关
后面还有条评论,点击查看>>