默认 Symfony ErrorHandler 返回 HTML 是因它不决定响应格式,而由 Accept 头和 DebugMode 决定;API 需通过 ExceptionListener 或 error_controller 强制 JSON 响应,并用 FlattenException 提取结构化错误信息。

为什么默认的 Symfony ErrorHandler 返回 HTML 而不是 JSON?
因为 Symfony\Component\ErrorHandler\ErrorHandler 本身不决定响应格式,它只负责捕获异常、记录、生成错误页面或调试信息;真正决定返回 HTML 还是 JSON 的,是请求的 Accept 头和当前环境下的 DebugMode 配置。开发环境下默认返回 HTML 错误页面(带堆栈),生产环境则可能返回空白 500 —— 完全不满足 API 场景。
如何让 API 请求强制走 JSON 错误响应?
核心是接管异常渲染流程,用 ExceptionListener 替换默认行为。你需要在 config/packages/dev/monolog.yaml 或主配置中禁用默认 HTML 渲染,并注册自定义监听器:
- 确保
framework.error_controller指向一个返回 JSON 的 controller(如error_controller: 'App\Controller\ErrorController::show') - 在
config/packages/framework.yaml中关闭 debug 模式对 API 请求的影响:debug: '%kernel.debug%'保持开启,但通过监听器判断request->getContentType() === 'json'或request->headers->get('Accept') === 'application/json' - 监听
kernel.exception事件,在监听器中检查是否为 API 请求(比如路径以/api/开头,或有X-Requested-With: XMLHttpRequest),然后手动构造JsonResponse
如何复用 Symfony 的错误信息但输出结构化 JSON?
不要丢弃 ErrorHandler 解析出的异常上下文(如 $exception->getMessage()、$exception->getCode()、$exception->getTraceAsString()),但要避免直接暴露堆栈(尤其生产环境)。推荐做法:
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
- 用
Symfony\Component\ErrorHandler\Exception\FlattenException::create($exception)获取标准化错误对象 - 提取
$flattened->getStatusCode()和$flattened->getStatusText()作为 HTTP 状态码和原因短语 - 生产环境只返回
message和code,开发环境可加trace字段(但需过滤敏感路径,如vendor/或src/下的具体行号) - 避免在 JSON 中嵌入完整 HTML 片段(比如
FlattenException::getAsString()返回的是 HTML 字符串)
常见踩坑:404 不触发你的 ExceptionListener?
因为 NotFoundHttpException 默认由路由层抛出,且某些情况会被 RouterListener 提前处理,导致 kernel.exception 事件没被触发。解决方式:
- 确认你的监听器优先级足够高(例如设为
priority: 20) - 在
config/packages/routing.yaml中确保strict_requirements: null,避免因参数验证失败提前返回 404 而绕过监听器 - 更稳妥的做法:把 404 处理逻辑也放进
error_controller,而不是只依赖异常监听 - 注意:如果用了 API Platform,它自带的
ExceptionListener会覆盖你的配置,需在api_platform.exception_to_status中显式映射异常类
真正难的不是格式美化,而是区分“谁该负责序列化”——是控制器、异常监听器,还是 error_controller。混用会导致重复渲染或状态码错乱。别图省事直接 throw new HttpException(400, 'xxx'),先看清楚你当前项目里哪一层已经接管了异常流。

















