hyperf全局异常控制器报错主因是配置不匹配、状态码未设及协程上下文丢失;需确保server name与exceptions.php中handler键名一致,handle方法显式调用withstatus()和stoppropagation(),并隔离协程日志与响应上下文。

Hyperf 创建全局异常控制器后输出报错,通常不是代码写错了,而是配置、注册或上下文链路断了。核心问题集中在三处:异常处理器没对上 Server 名称、HTTP 状态码没手动设置、或协程环境下日志/响应上下文丢失。
server name 和 exceptions.php 中 handler 键必须完全一致
Hyperf 会按 server 的 name 字段去匹配 config/autoload/exceptions.php 里的 handler 数组键名,大小写敏感、不能多空格、不能用别名。
- 运行
php bin/hyperf.php start,看启动日志里类似[INFO] Server started: http://0.0.0.0:9501这行,前面的name值就是真实标识(比如http、api、admin) - 打开
config/autoload/server.php,确认 HTTP server 配置块中'name' => 'xxx'的值 - 打开
config/autoload/exceptions.php,确保'handler' => ['xxx' => [...]]中的xxx和上一步一模一样 - 如果写成
'http'但实际 server name 是'api',你的异常处理器根本不会被调用,请求直接走框架默认兜底,可能返回空白或 500
handle() 方法里必须手动设置 status 并调用 stopPropagation()
Hyperf 不会自动把异常构造函数里的 code 映射为 HTTP 状态码,也不会自动终止异常传递链。
-
$response->withStatus(422)或withStatus(500)必须显式调用,否则默认是 500,且前端收不到你想要的状态 -
$this->stopPropagation()必须在 handle() 里执行,否则异常继续往下传,可能被后面的 HttpExceptionHandler 拦截,导致你写的格式化响应失效 - 不要只写
return $response->json([...])就完事,status 和传播控制缺一不可
验证中间件和异常处理器是否真正启用
尤其验证类异常(如 ValidationException)容易“静默失败”,表面没报错,实际 errors 字段为空或返回 500 而非 422。
- 确认已执行
php bin/hyperf.php vendor:publish hyperf/validation和hyperf/translation - 检查
config/autoload/middlewares.php的http数组是否包含Hyperf\Validation\Middleware\ValidationMiddleware::class - 检查
config/autoload/exceptions.php的对应 server 下是否注册了Hyperf\Validation\ValidationExceptionHandler::class - 自定义 ValidationExceptionHandler 时,确保返回的是
$throwable->validator->errors()->messages(),而不是只取first()
协程环境下的响应与日志要隔离上下文
Worker 进程里多个请求共用一个协程,不主动注入 request_id 或 correlation_id,会导致响应错乱、日志混杂、堆栈丢失。
- 在 Controller 入口或中间件里,用
\Hyperf\Context\Context::set('request_id', $request->getAttribute('request_id')) - 自定义 Formatter 时,从 Context 读取 request_id 写入日志,别依赖
$_SERVER或全局变量 - 日志方法调用时带上上下文字典:
$logger->error('order failed', ['rid' => $rid, 'uid' => $uid]) - 协程报错堆栈丢失?检查
config/autoload/logger.php中 LineFormatter 构造参数第四个设为true(include_stacktraces)











