Hyperf 全局异常处理通过 ExceptionHandler 实现而非中间件,因中间件无法捕获流程中断后的异常;需自定义继承 ExceptionHandler 的类并重写 render() 方法,在开发环境返回带堆栈的 JSON 响应,生产环境须禁用详细信息。

Hyperf 中全局异常处理不依赖中间件,而是通过 异常处理器(ExceptionHandler) 实现。中间件本身不捕获未抛出的异常,无法直接输出报错栈;真正负责统一捕获、格式化并响应异常的是 ExceptionHandler 类。
为什么不用中间件处理全局异常
Hyperf 的中间件链在请求正常流转时执行,一旦控制器或服务中抛出未被捕获的异常,流程会立即中断,跳过后续中间件,交由框架内置的异常处理机制接管。试图在中间件里用 try/catch 包裹 $next() 只能捕获该中间件内或其上游抛出的异常,无法覆盖全局。
正确方式:自定义 ExceptionHandler
Hyperf 默认已注册 Hyperf\HttpServer\Exception\Handler\ExceptionHandler,但默认仅返回简单错误信息。要输出完整报错栈,需继承并重写 render() 方法:
- 创建新类,如
App\Exception\GlobalExceptionHandler - 继承
Hyperf\Contract\ExceptionHandlerInterface或官方基类 - 在
render()中获取$throwable->getTraceAsString()或使用debug_backtrace()格式化 - 注意生产环境应关闭详细栈信息,仅开发环境启用
示例代码(开发环境可用)
在 app/Exception/GlobalExceptionHandler.php 中:
namespace App\Exception;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Psr\Http\Message\ResponseInterface;
use Throwable;
class GlobalExceptionHandler extends ExceptionHandler
{
public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface
{
// 记录日志(可选)
$this->container->get(StdoutLoggerInterface::class)->error($throwable->getMessage(), [
'file' => $throwable->getFile(),
'line' => $throwable->getLine(),
'trace' => $throwable->getTraceAsString(),
]);
// 开发环境返回带堆栈的 JSON 响应
$data = [
'message' => $throwable->getMessage(),
'file' => $throwable->getFile(),
'line' => $throwable->getLine(),
'trace' => $throwable->getTraceAsString(),
];
return $response->withStatus(500)
->withHeader('Content-Type', 'application/json; charset=utf-8')
->withBody(new \Hyperf\HttpMessage\Stream(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)));
}
public function isValid(Throwable $throwable): bool
{
return true; // 拦截所有异常
}
}
注册到 DI 容器
在 config/autoload/exceptions.php 中注册:
return [
'handler' => [
App\Exception\GlobalExceptionHandler::class => [
'priority' => 100,
],
],
];
确保该文件存在且被加载(Hyperf 3.x 默认启用)。若使用 Hyperf 2.2+,也可在 config/autoload/dependencies.php 中绑定接口。
安全提醒
切勿在生产环境返回完整堆栈——可能泄露路径、配置、数据库结构等敏感信息。建议:
- 通过
env('APP_ENV') === 'dev'控制是否输出 trace - 对
message和trace做脱敏处理(如过滤密码、token 字段) - 配合 Sentry、Logstash 等工具集中收集异常,而非直接暴露给前端


















