Laravel 通过 App\Exceptions\Handler 自动启用自定义异常处理,需创建实现 Responsable 的业务异常类,在 render() 中精准拦截并委托未匹配异常,在 report() 中按类型分流日志,API 与网页请求可差异化响应。

直接在 App\Exceptions\Handler 类里改 render() 和 report() 方法就能启用自定义异常处理,不需要额外注册或启动——Laravel 启动时自动绑定该类为全局异常处理器。
1. 创建业务异常类(必须实现 Responsable)
不推荐用 throw new Exception(),它会被当成 500 错误,前端收不到正确状态码和业务 code。应新建带语义的异常类,比如:
- 类名以
Exception结尾(如InsufficientBalanceException),便于 IDE 识别和静态分析 - 继承
RuntimeException或Exception,并实现Illuminate\Contracts\Support\Responsable -
toResponse()方法必须返回Illuminate\Http\Response实例,不能只返回数组
示例:
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
namespace App\Exceptions;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class InsufficientBalanceException extends \RuntimeException implements Responsable
{
public function toResponse(Request $request): Response
{
return response()->json([
'code' => 'balance_insufficient',
'message' => $this->getMessage(),
], 402);
}
}
2. 在 Handler::render() 中精准拦截
不要写 instanceof Exception 这种宽泛判断,否则会覆盖 Laravel 内置异常(如 ModelNotFoundException 导致 404 不显示)。只对明确业务异常做分支处理:
- 匹配你定义的异常类型,例如
$exception instanceof InsufficientBalanceException - 所有未匹配的异常,必须交还给
parent::render($request, $exception),否则调试、Telescope、日志链路会中断 - 如果是 API 请求,可统一返回 JSON;如果是网页请求,也可返回视图(如
response()->view('errors.payment-failed'))
3. 在 Handler::report() 中分流日志
异常响应和日志记录是两件事。report() 负责归档,可按类型写入不同渠道:
- 用
instanceof判断异常类型,调用Log::channel('payment')->error()等定向记录 - 不要在异常类内部写日志逻辑——它可能在队列、命令行中被抛出,此时 HTTP 上下文不存在
- 敏感信息(如用户 ID、订单号)可从
$exception属性或$request中提取后注入日志上下文
4. 配合错误页面(非 API 场景)
如果项目同时服务网页和 API,可在 render() 中区分请求类型:
- 检测
$request->expectsJson()或路径前缀(如$request->is('api/*'))决定返回 JSON 还是视图 - 通用 HTTP 错误页放在
resources/views/errors/404.blade.php等位置,Laravel 会自动匹配 - 要预览这些页面,需设
APP_ENV=production且APP_DEBUG=false

















