没有百分百不出错的代码,就像没有完美的人一样。有效的捕获程序执行过程中产生的未知异常,确保程序的健壮是一件很重要的事。

Laravel 有很多内置的异常处理,一般我们使用:

throw new Exception('不好意思,出错了');

根据 .env 文件配置项:APP_DEBUG=true or false

如果是在开发环境APP_DEBUG=true,触发了这个异常,会看到:


如果是生产环境:


这种提示对用户很不友好,接下来我们定制下异常。通常情况下,异常可分为两大类,用户行为类和内部错误。顾名思义,用户行为类是用户不正当的操作触发了异常,通常这类异常是不需要写入日志的,捕获到什么错误信息通常直接返回告知用户;而服务器内部错误触发的异常,则需要写入日志,便于分析查找原因,而这类错误直接抛给用户是毫无意义的,因为用户根本解决不了啥问题,也有可能给别有用心的人盯上,这时,直接告知用户“ 服务器内部错误 ”即可。

这里,分别介绍这两个不同性质的异常。

    用户错误行为触发的异常
>$ php artisan make:exception InvalidRequestException

处理用户行为异常代码如下:

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Http\Request;
use Throwable;

class InvalidRequestException extends Exception
{
public function __construct( string $message = "", int $code = 0, Throwable $previous = null )
{
parent::__construct($message, $code, $previous);
}

/**
* 一旦异常被触发,执行 render() 方法
* @param Request $request
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\JsonResponse|\Illuminate\View\View
*/
public function render( Request $request )
{
if ( $request->expectsJson() ) {
return response()->json(['msg'=>$this->getMessage()], 400);
}
return view('pages.error', ['msg'=>$this->getMessage()]);
}
}

调用:

...

use App\Exceptions\InvalidRequestException;
...
throw new InvalidRequestException('非法参数');

自动判断了,是否是 ajax 提交,是的话就返回 json,否则显示错误页面。

自定义错误页面:/resources/views/pages/error.blade.php

@extends('layouts.app')

@section('title', '错误')

@section('content')
<div>
<div>错误</div>
<div>
<h1>{{ $msg }}</h1>
<a href="{{ route('root') }}">返回首页</a>
</div>
</div>
@endsection
    系统内部异常
>$ php artisan make:exception InternalException

处理系统内部异常代码如下:  

<?php
namespace App\Exceptions;

use Exception;
use Illuminate\Http\Request;
use Throwable;

class InternalException extends Exception
{
protected $msgForUser;

public function __construct( string $message = "", string $msgForUser = '系统内部错误', $code = 500, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->msgForUser = $msgForUser;
}

public function render( Request $request )
{
/**
* 判断开发环境 如果是开发或测试 则显示详细信息;线上返回内部错误
*/
if ( env('APP_DEBUG') ) {
// 开发环境
if ( $request->expectsJson() ) {
return response()->json(['msg'=>$this->getMessage(), 'code'=>$this->getCode()], $this->getCode());
}
return view('pages.error', ['msg'=>$this->getMessage()]);
} else {
// 生产环境
if ( $request->expectsJson() ) {
return response()->json(['msg'=>$this->msgForUser, 'code'=>$this->getCode()], $this->getCode());
}
return view('pages.error', ['msg'=>$this->msgForUser]);
}
}
}

这个异常的构造函数第一个参数就是原本的异常错误信息,比如redis服务连接不上等;第二个参数是展示给用户的信息。

    日志处理

Laravel 触发异常时,默认的会将错误信息和调用栈打印到日志文件中。如果是用户行为类异常,因为不影响系统的正常运行,所有没有必要记录到日志。

屏蔽指定异常写入日志:/app/Exception/Handler.php

...
protected $dontReport = [
InvalidRequestException::class,
];
...

至此,简单的异常处理基本上完成了。

由于能力有限,不足或有不解之处,希望在下方评论区与我讨论,共同提高 。