先确认是否注册成功:运行php bin/console debug:event-dispatcher kernel.exception查看监听器是否列出,再清缓存、检查标签拼写、web服务器拦截及优先级冲突。

kernel.exception 监听器没生效?先确认是否注册成功
监听 kernel.exception 事件失败,最常见原因是服务根本没注册进事件分发器。别急着改逻辑,先验证基础链路:
- 运行
php bin/console debug:event-dispatcher kernel.exception,看输出里有没有你的监听器类名;没出现就说明 YAML 配置漏了、路径写错、或标签拼错(比如kernel.event_listerner少个e) - 检查
services.yaml中是否用了自动配置但类名不规范:默认只扫描含Listener或Subscriber的类名,如果叫MyErrorCatcher就不会被自动发现 - 开发环境记得清缓存:
php bin/console cache:clear --env=dev,否则旧注册表还在用
访问无效路径时没触发监听器?可能是 Web 服务器拦截了
Symfony 还没机会跑 kernel.exception,Nginx/Apache 就直接返回 404 了。这种情况在生产环境特别常见:
- 检查 Nginx 配置里有没有
fastcgi_intercept_errors on;—— 如果开了,PHP 错误页会被 Web 服务器吞掉,kernel.exception根本收不到 404 异常 - 改成
fastcgi_intercept_errors off;,让 Symfony 接管所有响应 - Apache 下对应的是
FallbackResource或ErrorDocument配置,确保 404 被转发到app.php或index.php
监听器里记录日志但看不到内容?注意异常类型和环境差异
kernel.exception 只捕获 Exception 和 Throwable,对 404 这类路由未匹配错误,Symfony 实际抛的是 NotFoundHttpException(它继承自 HttpException,属于 Exception),所以能被捕获。但以下情况会失效:
- 控制器里写了
try/catch并吞掉了异常,事件根本不会发出 - 某些 Bundle(如 FOSUserBundle)自带异常监听器且优先级更高(默认
priority: 0),它调用了$event->setResponse(),后续监听器就被跳过了 —— 给你的监听器加priority: 10试试 - 生产环境默认关闭调试,
exception事件仍触发,但堆栈信息被过滤;确认monolog配置里level: error以上日志没被静默丢弃
记录“无效路径”访问,别只记 URL,带上上下文才好排查
单纯记录 $request->getPathInfo() 不够,很多 404 是带 query 参数或 header 特征的攻击试探:
- 在监听器里补全关键字段:
$request->getClientIp()、$request->headers->get('User-Agent')、$request->getMethod() - 避免记录敏感值:别打
$exception->getTraceAsString()到日志文件,尤其生产环境;用error_log()或 Monolog 的context参数结构化传入 - 区分真实业务异常和爬虫乱扫:
if ($exception instanceof NotFoundHttpException && $request->isXmlHttpRequest())可单独标记为前端资源加载失败,不用告警
真正难处理的不是监听器写不写得出来,而是异常发生时请求上下文已经残缺 —— 比如容器可能还没完全初始化,$this->container 不可用,依赖注入的服务得提前声明好,不能临时找。











