webman全局异常捕获需配置config/exception.php中''键注册处理器,类实现exceptionhandlerinterface并置于psr-4可加载路径;render()须显式设json头、返回response()->json(),区分businessexception与exception以精准告警,透传trace_id及上下文,告警异步化,中间件须前置注入。

线上环境出异常,光靠var_dump或echo根本来不及——等你登录服务器翻日志,用户可能已经批量投诉了。Webman 的全局异常捕获必须做到:错误发生时立刻知道「哪条请求、哪个类、哪行代码、什么类型异常」,同时触发告警,而不是只返回一个空泛的 500 Internal Server Error。
config/exception.php 配置必须用空字符串键
Webman 不会自动识别你写的异常处理器,除非它被注册在配置数组的 '' 键下。写成 'default'、'app' 或留着注释行 // '' => ... 都无效,框架直接跳过,退回到默认 HTML 错误页。
- 必须删掉 config/exception.php 中所有注释掉的注册行,避免干扰
- 路径要能被 PSR-4 自动加载,推荐放在
app/exception/ExceptionHandler.php - 类必须实现
Webman\Exception\ExceptionHandlerInterface,否则启动时报致命错误 - 如果用了 Composer autoload,改完类名或命名空间后记得执行
composer dump-autoload -o
render() 方法里不设 header 就不是 JSON
即使你 return 了一个数组,Webman 也不会自动加 Content-Type: application/json,浏览器收到的是裸文本或 HTML,前端 fetch 的 response.json() 直接抛错。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 开头必须显式写
header('Content-Type: application/json; charset=utf-8'); - 返回值必须是
support\Response实例,不能直接return ['code' => 500] - 最稳妥写法是
return response()->json(['code' => 500, 'msg' => $e->getMessage(), 'trace_id' => uniqid('tr_')]); - 手动
json_encode()时务必加JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR,否则中文乱码或静默失败
区分 BusinessException 和 Exception 才能精准告警
业务异常(比如参数校验失败、权限不足)和系统异常(数据库连不上、内存溢出)的处理逻辑完全不同:前者不该发告警,后者必须立刻通知。
- 用
$e instanceof support\exception\BusinessException判断是否为业务异常 - 业务异常建议返回
400或401,并跳过告警通道;普通Exception才走告警流程 - 在
render()里不要 try-catchjson_encode(),它已设JSON_THROW_ON_ERROR,让框架 fallback 到 raw text 更安全 - 生产环境禁用
$e->getTraceAsString(),路径和变量值可能含敏感信息;如需上下文,只取$e->getFile()+$e->getLine()+$e->getCode()
告警触发前必须加 trace_id 和上下文透传
没有唯一请求标识的告警等于废告警。同一个异常反复触发,你无法判断是单点故障还是全量崩溃;没有用户 ID、URL、IP,排查时就得盲猜。
- 在中间件中生成
trace_id并存入context(如Context::set('trace_id', $id)),确保异常处理器能读到 - 告警内容至少包含:
trace_id、request_uri、remote_ip、user_id(如有)、exception_class、file:line - 避免在
render()里调用耗时操作(如 HTTP 请求、DB 查询),告警应异步投递到消息队列或本地日志文件,再由独立进程统一上报 - 别依赖
$_SERVER['REQUEST_URI'],Webman 可能已重写过路由;优先用request()->uri()或request()->fullUrl()
最容易被忽略的一点:中间件顺序。如果你的日志中间件在异常处理器之后注册,那 trace_id 和请求上下文就压根没机会写入——异常一抛,流程就断了。务必把 trace 注入、请求日志这类前置中间件放在 config/middleware.php 的最顶部。









