TP6全局异常处理默认仅覆盖HTTP请求,CLI、队列、定时任务异常不触发ExceptionHandler;需在public/index.php用set_exception_handler兜底,队列Job须手动try/catch,render()应判isAjax()/expectsJson()/routeIs('api.*')并用response()->json()返回,邮件配置须严格按mail.php约定且云服务器需开放587端口。

TP6 的全局异常处理默认只覆盖 HTTP 请求,命令行、队列、定时任务里的异常根本不会走 ExceptionHandler —— 这是线上告警漏报最常见原因。
为什么改了 app/exception/Handler.php 但 CLI 异常还是原样打印?
因为 TP6 的 app_exception 配置只在 HTTP 生命周期中生效。php think command、queue:work、或者 php think run 启动的进程,压根不加载这个配置。
- 必须在
public/index.php底部加set_exception_handler()兜底,例如:set_exception_handler(function($e) { \think\facade\Log::error('Uncaught exception: ' . $e->getMessage()); dispatch(new \app\job\SendAlertEmailJob($e)); }); - 队列 Job 必须手动
try/catch:TP6 不会自动包裹handle()方法,漏写就等于放弃监控 - 不要在
set_exception_handler()里调用register_shutdown_function(),否则Fatal error类错误会被吞掉,日志全无
render() 返回 JSON 却被套上 HTML 模板?
不是你的 JSON 写错了,是 TP6 默认按 Accept 头或 URL 后缀判断格式。Postman、curl、fetch(没设头)都 fallback 到 HTML。
- 在
render()开头加判断:$request->isAjax() || $request->expectsJson() || $request->routeIs('api.*') - 别用
return json([...])—— 它绕过响应生命周期,状态码和中间件全失效;改用return response()->json([...], 500) - 确保
config/app.php中'show_error_msg' => false(生产环境),否则敏感路径、SQL 仍会泄露
邮件告警发不出去,Connection could not be established with host smtp.qq.com 怎么办?
90% 是配置键名错或端口被封,不是密码问题。
立即学习“PHP免费学习笔记(深入)”;
-
config/mail.php必须存在,且只认这些 key:host(不带ssl://)、port(QQ 用587,不是465)、username(完整邮箱)、password(SMTP 授权码,非登录密码)、from.address和from.name缺一不可 -
.env里的MAIL_*变量 TP6 完全不读,写了也白写 - 云服务器(阿里云/腾讯云)默认封
25和465端口,必须开587并确认安全组放行
真正难搞的不是配置,是异常类型判断逻辑 —— HttpException(比如 404)默认不进 render(),BaseException 子类可能被框架隐式转成 HttpException,而 report() 里又得手动裁剪 trace 长度、过滤 $_SERVER 敏感字段。这些边界条件不逐个验证,监控就永远有盲区。


















