最稳妥的是用 json() 方法,因其自动处理状态码、content-type、utf-8编码及中间件拦截;手动 echo json_encode() 会导致头信息缺失、状态码无法自定义、中文乱码及钩子失效。

直接用 json() 方法最稳妥,别手动 json_encode() + header(),否则 Content-Type 和状态码容易出错。
为什么不能直接 echo json_encode()?
ThinkPHP 的响应对象(Response)会自动处理 HTTP 状态码、字符编码、Content-Type 头和输出缓冲。手动 echo json_encode() 会绕过这些机制,导致:
- 返回头缺失
Content-Type: application/json,前端可能解析失败 - HTTP 状态码默认是 200,但业务错误时需返回 4xx/5xx,手动写难同步
- 中文乱码风险(没设置 UTF-8 编码或没调用
defaultCharset) - 后续中间件或钩子(如日志、CORS)无法拦截响应内容
tp6 中推荐的三种 json 返回方式
ThinkPHP 6+ 响应对象已统一为 think\Response,以下方式都基于控制器中 $this->success() 或 return json() 展开:
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
-
return json($data):最常用,自动设Content-Type和 UTF-8 编码,支持传入状态码、Header 数组等可选参数 -
return $this->success($msg, $data, $code = 200):封装好的语义化方法,返回结构固定({code: 1, msg: "...", data: ...}),适合前后端约定格式的项目 -
return json($data)->code(400)->header(['X-Api-Version' => 'v2']):链式调用,适合需要自定义状态码或 Header 的场景(如接口版本标头)
常见踩坑点:数组键名、空值和 JSON_UNESCAPED_UNICODE
ThinkPHP 默认使用 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,但仍有几个细节要注意:
- 关联数组键名含中文?没问题,TP6 默认开启
JSON_UNESCAPED_UNICODE,不会转成 \uXXXX - 数据里有
null或NaN?PHPjson_encode()会返回null或报错,建议提前过滤(如用array_filter($data, function($v) { return $v !== null; })) - 想兼容 IE8?得加
JSON_FORCE_OBJECT,但 TP6 不直接暴露 flags 参数,需自己 new Response:return Response::create($data, 'json')->options(['json_encode_param' => JSON_FORCE_OBJECT]) - 调试时发现返回的是 HTML 页面?检查是否漏了
return,或被前置中间件(如未登录跳转)拦截了响应
tp5.1 与 tp6 的关键差异
tp5.1 的 json() 是助手函数(本质是 Response::create(..., 'json')),而 tp6 把它升级为响应类的静态方法,行为更一致:
- tp5.1:
return json($data, 200, [], JSON_PRETTY_PRINT)—— 第四个参数是json_encode()的 flags - tp6:
return json($data)->code(200)->options(['json_encode_param' => JSON_PRETTY_PRINT])—— flags 必须走options(),直接传参会报错 - tp6 默认关闭
JSON_PRETTY_PRINT,如需美化格式(仅开发用),必须显式配置,否则压缩后无换行缩进
真正要留意的是:不是所有「返回 JSON」的需求都该用 json()。比如导出大文件流、SSE 推送、或需要分块输出的场景,得用 Stream 响应类型,硬套 json() 会内存溢出。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










