所有 symfony 控制器必须返回 response 对象,否则抛出 unexpectedvalueexception;返回 json 应用 jsonresponse 或 $this->json(),禁用 json_encode()+response;禁止直接传 doctrine 实体;api 异常需通过 kernel.exception 监听器统一返回 json 响应。

所有 Symfony 控制器最终必须返回一个 Response 对象,这是框架硬性要求;不返回、返回 null、或返回非 Response 实例(比如数组、字符串、void)都会触发 UnexpectedValueException: Controller must return a "Symfony\Component\HttpFoundation\Response" object。
用 JsonResponse 返回 JSON 时别手写 json_encode()
常见错误是手动 json_encode() + Response:它漏设 Content-Type: application/json,且不处理 null、NAN、UTF-8 BOM 等边界情况,前端常收不到有效 JSON 或解析失败。
- 正确做法:
use Symfony\Component\HttpFoundation\JsonResponse;,然后return new JsonResponse($data),$data可以是数组、标量、或实现JsonSerializable的对象 - 状态码直接传第二参数:
new JsonResponse(['error' => 'not found'], 404) - 禁止传 Doctrine 实体对象——会因循环引用(如
User↔Post)崩溃,或触发 N+1 查询(Proxy 加载) - 简单场景下,优先调用实体的
toArray()方法(需你自行定义),而非get_object_vars()(暴露私有属性和代理内部字段)
用 $this->json() 快捷方法要注意请求格式协商
$this->json() 是 AbstractController 提供的快捷封装,本质仍是 JsonResponse,但它会读取 $request->getRequestFormat()。如果路由没配 format 或 Accept 头不匹配,可能意外 fallback 到 HTML 渲染。
- 确保路由明确声明 JSON 场景,例如:
@Route("/api/users", name="api_users", defaults={"_format"="json"}) - 或在控制器里显式判断:
if ('json' !== $request->getRequestFormat()) { throw $this->createAccessDeniedException(); } - 该方法不支持自定义序列化组(groups)、上下文(context),需要深度控制时,应退回到手动构造
JsonResponse或使用Serializer
返回二进制文件必须用 BinaryFileResponse
用普通 Response 输出文件内容(比如 file_get_contents() + Response)会把整个文件加载进内存,大文件直接 OOM;且无法设置标准 Content-Disposition、Last-Modified 等头。
- 正确方式:
use Symfony\Component\HttpFoundation\BinaryFileResponse;,然后return new BinaryFileResponse($filePath) - 强制下载:
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'report.pdf') - 确保
$filePath是绝对路径(如/var/www/project/public/files/data.zip),相对路径会报FileNotFoundException - Web 服务器(如 Nginx)可接管静态文件响应,此时应配置
fastcgi_hide_header X-Sendfile;并启用X-Accel-Redirect,避免 PHP 进程阻塞
自定义 404/500 响应要监听 kernel.exception
直接在控制器里 throw new NotFoundHttpException() 会走默认 HTML 模板,API 场景下前端收不到 JSON 错误体。
- 必须新建监听器类(如
App\EventListener\ApiExceptionListener),在onKernelException()中捕获NotFoundHttpException或HttpException - 用
$event->setResponse(new JsonResponse(['error' => 'Not Found'], 404))替换默认响应 - 优先级设为
10(高于默认0),否则被 Symfony 内置异常处理器覆盖 - 别忘了检查请求是否来自 API 路由(如前缀
/api/或 Accept 头含application/json),避免把网页 404 也转成 JSON
最易忽略的是 Doctrine 实体直接进 JsonResponse —— 开发环境可能因缓存或简化配置不报错,一上生产就 500;还有 BinaryFileResponse 路径写错导致 404 却不报具体文件缺失,只显示空白响应。











