hyperf 中崩溃信息必须由 exceptionhandler 捕获而非事件监听,因未捕获的 throwable 直接触发异常处理器链;需在 config/autoload/exceptions.php 注册 handler,匹配后调用 handle() 并 stoppropagation(),手动设置响应状态码与结构化日志。

Hyperf 中程序崩溃信息不能靠“监听异常事件”来捕获,因为真正的崩溃(如未捕获的 Throwable)走的是 异常处理器链(ExceptionHandler),不是事件系统。事件(Event)只适合解耦、通知类逻辑,比如“异常已处理完毕后发告警”,但无法替代异常捕获本身。
崩溃信息必须由 ExceptionHandler 输出
Worker 进程一旦遇到未捕获异常,默认会直接退出,导致服务中断。Hyperf 要求你显式注册 ExceptionHandler 来接管它:
- 所有业务代码中未用
try/catch包裹的异常,都会被路由到config/autoload/exceptions.php中配置的 handler 链 - handler 按数组顺序逐个调用
isValid()判断是否匹配,匹配后执行handle() - 必须在
handle()中调用$this->stopPropagation(),否则异常继续往下传,可能被兜底 handler 覆盖或漏记日志 - 响应状态码不会自动从异常构造参数映射,需手动调用
$response->withStatus(500);业务错误码建议放在 JSON body 的code字段里,而非 HTTP status
日志记录要带上下文才可追溯
单纯 error_log() 或 file_put_contents() 打印堆栈,无法关联请求。正确做法是结构化记录请求上下文:
- 从容器获取
RequestInterface,提取getMethod()、url()、all()等字段 - 捕获
$throwable->getMessage()、getFile()、getLine()、getTraceAsString() - 协程环境下必须注入
correlation_id或使用\Swoole\Coroutine::getCid(),否则多请求日志混杂 - 推荐用
Monolog\Formatter\LineFormatter并开启include_stacktraces = true,确保堆栈完整输出
别误用 Event 去“捕获崩溃”
事件机制(如 ExceptionOccurred)本质是“异常已被某个 handler 处理完后触发的通知”,不是拦截点:
- 它无法阻止进程退出,也不能修改响应内容
- 若你在监听器里再抛异常,反而可能引发二次崩溃
- 适合场景:记录审计日志、推送企业微信告警、上报 Sentry——这些都发生在 handler 已完成响应之后
- 想打印崩溃原始信息?请检查你的
AppExceptionHandler是否真被调用,而不是等 Event 触发才写日志
验证是否生效的实操步骤
快速确认异常路径是否通:
- 故意在控制器里 throw new RuntimeException('crash test')
- 查看
runtime/logs/hyperf.log是否有完整堆栈和请求路径 - 用 curl 测试响应体是否含
{"code":500,"message":"..."},状态码是否为 500 - 检查
ps aux | grep worker,确认 Worker 进程没因该异常退出











