hyperf 默认静默吞掉未配置处理器的异常,需正确注册、精准匹配、确保冒泡:httpexceptionhandler 必须排第一,自定义处理器 isvalid() 要严格限定类型;调试时启用 -d 参数和 debug 日志级别,并验证是否真被未捕获。

Hyperf 默认会静默吞掉未配置处理器的异常,导致开发时看不到错误堆栈、日志不完整,甚至 Worker 进程意外退出。要让未捕获异常清晰可见,关键不是“打开开关”,而是**正确注册、精准匹配、确保冒泡**。
确认异常处理器已注册且顺序合理
打开 config/autoload/exceptions.php,检查 http 类型下的 handler 数组:
- Hyperf 内置的
HttpExceptionHandler必须在最前,它专管 404、405 等 HTTP 状态异常,不能被自定义类拦截 - 自定义处理器(如
AppExceptionHandler)应放在其后,且isValid()方法必须严格限定异常类型,避免return true无差别接管 - 如果所有异常都希望透出原始信息用于调试,可临时把自定义 handler 注释掉,只留框架默认 handler
让未捕获异常强制打印到控制台和日志
Hyperf 的 HttpExceptionHandler 默认已将异常写入日志,但若你发现控制台没输出,需确认两点:
- 运行命令是否带
-d或--debug参数(如php bin/hyperf.php start -d),否则部分 debug 日志可能被抑制 - 检查 config/autoload/logger.php 中
default日志通道的level是否设为'debug'或更低 - 确保
HttpExceptionHandler::handle()中的$this->logger->debug(...)没被覆盖或禁用
验证异常是否真被“未捕获”
常见假象:你以为是未捕获,其实是被某处提前吞了。快速验证方法:
- 在任意 Controller 方法中直接写
throw new RuntimeException('test uncaught'); - 访问接口,观察终端输出 —— 应看到完整堆栈、HTTP 状态 500、响应体含错误信息
- 同时检查 runtime/logs/ 下当日日志文件,确认该异常已落盘
- 若无任何输出,说明异常被某个
try/catch、全局set_exception_handler或中间件拦截,需逐层排查
避免协程环境下异常丢失
在异步任务(如 AsyncQueue Job)、定时器或协程内抛出的异常,不会走 HTTP 异常处理器链。这类异常需单独对待:
- AsyncQueue 任务中,
handle()抛出的异常由 async-queue 组件自身处理,会进 failed 队列,但不会触发http类型的 handler - 协程内 DB 查询、Redis 调用失败,若用的是非协程安全驱动(如原生 PDO),可能引发致命错误而非可捕获异常,此时需改用
Hyperf\Database\Connection等协程适配版本 - 如需统一记录,可在协程启动处手动包一层
go(function () { try { ... } catch (\Throwable $e) { logger()->error(...); throw $e; } });











