在 Symfony 中,应通过自定义 NotFoundListener 监听 kernel.exception 事件,优先级设为 10,在 onKernelException 中捕获 NotFoundHttpException 并返回 JsonResponse,同时根据请求格式或路由前缀区分 API/网页请求,并记录日志。

在 Symfony 中,重写 404 响应的返回值(比如返回 JSON 而非 HTML)通常不是靠修改 ExceptionListener 类本身,而是通过自定义异常监听器并针对 NotFoundHttpException 做专门处理来实现。
监听 NotFoundHttpException 并返回 JSON
默认情况下,Symfony 的错误页面由 Twig 模板渲染,但你可以创建一个专用的异常监听器,在捕获到 404 异常时主动构造 JSON 响应。
- 创建监听器类(如
App\EventListener\NotFoundListener),注入RequestStack和JsonResponse相关服务 - 在
onKernelException方法中判断$event->getThrowable()是否为NotFoundHttpException - 调用
$event->setResponse(new JsonResponse(...))替换默认响应 - 确保该监听器优先级高于默认异常处理(例如设为
0或更高,负数优先级更低)
配置监听器并设置优先级
在 services.yaml 中注册监听器,并指定事件和优先级:
App\EventListener\NotFoundListener:
tags:
- { name: 'kernel.event_listener', event: 'kernel.exception', method: 'onKernelException', priority: 10 }优先级设为正数(如 10)可确保它早于 Symfony 默认的 ExceptionListener(优先级为 0)执行,从而拦截并覆盖 404 响应。
区分环境与请求格式
实际项目中往往只对 API 请求返回 JSON,而网页请求仍走 HTML 页面。可通过以下方式判断:
- 检查
$request->getRequestFormat()是否为'json'或'api' - 检查
$request->headers->get('Accept')是否包含application/json - 或根据路由前缀(如以
/api/开头)做条件判断
这样能避免全局替换导致普通页面也变成 JSON,破坏用户体验。
保持原有日志与调试信息
重写响应时不要跳过异常日志记录。建议保留原始异常堆栈(尤其在 dev 环境):
- 使用
$this->logger->warning('Resource not found', ['exception' => $e])记录日志 - 开发环境下可将
debug信息加入 JSON(如'debug' => $e->getMessage()),生产环境则隐藏 - 避免直接抛出新异常或静默吞掉错误,否则难以排查问题


















