根本原因是ThinkPHP默认按HTML模板流程渲染数组,而非JSON响应;需显式调用json()、配置default_return_type为'json',或自定义异常处理器以统一返回JSON。

ThinkPHP 直接 return 数组却返回 HTML 页面,根本原因不是数组本身有问题,而是框架没把它当 API 响应处理——它默认走的是模板渲染流程,最终把数组丢进视图引擎里,再套上 layout 模板,结果输出了一整页 HTML。
为什么 return [] 会触发 HTML 渲染
ThinkPHP 的控制器方法返回值会被 thinkResponse 自动封装。当你 return $data(比如一个数组),框架会检查当前请求是否满足「JSON 响应条件」:
- 没启用
default_return_type => 'json'配置,且 - 请求头不含
Accept: application/json或X-Requested-With: XMLHttpRequest,且 - 没在方法里显式调用
json()、success()等响应构造函数
三者全不满足时,框架就按默认逻辑走:把数组传给模板(如 index.html),再用 view() 渲染成 HTML 返回。你看到的“空白页”或“Array to string conversion”错误,本质是模板试图把数组当字符串 echo 出来。
tp5/tp6 中让 return 数组变成 JSON 的两种可靠方式
别依赖请求头自动识别,手动指定最稳:
立即学习“PHP免费学习笔记(深入)”;
-
return json($data)—— 最简方案,TP5.1+ 和 TP6 都支持,自动设 Content-Type 和状态码 -
return response($data)->contentType('application/json')—— 更底层,适合需要自定义 Header 的场景(如加X-Response-Time) - 全局改配置(仅限纯 API 项目):
config/app.php中设'default_return_type' => 'json',但注意:这会让所有控制器返回都走 JSON,包括你本意想渲染 HTML 的后台页面
⚠️ 切勿写 echo json_encode($data); exit; —— 绕过框架响应生命周期,日志、中间件、钩子全失效。
API 异常也返回 HTML?那是异常处理器没对齐
即使你 controller 里写了 return json(...),一旦抛出异常(如数据库连接失败、模型字段不存在),默认异常处理器仍会返回 HTML 错误页。这是因为异常捕获发生在响应生成之前,不受 default_return_type 控制。
- 必须自定义异常类,继承
thinkexceptionHandle,重写render()方法 - 在
render()里判断请求类型:if ($request->isAjax() || $request->header('accept') === 'application/json'),然后return json([...]) - 别忘了在
app.php配置中绑定:'exception_handle' => '\app\exception\JsonException'
否则,哪怕 99% 的接口都正常返回 JSON,只要一个 Db::table('xxx')->find() 找不到表,前端收到的就是 500 HTML 页面。
容易被忽略的兼容细节
TP6.0+ 默认开启 middleware,而某些中间件(如 LoadLangPack)会在响应前修改输出;TP5.1 的 json() 不支持对象自动转数组,TP6 则支持。更隐蔽的是:
- 控制器方法末尾多了一个空格或 BOM,导致 PHP 输出提前触发,后续
json()失效(报 Headers already sent) - 用了
dump()、print_r()调试后忘记删,同样触发提前输出 - PHP 版本差异:TP6.3+ 对
json($data, 256)的 flag 支持更严格,旧写法可能静默降级
真正卡住人的从来不是「怎么写」,而是「为什么明明写了 json 却还是 HTML」——往往就差一个配置开关、一次未清理的调试输出,或者异常处理器和控制器返回逻辑没对齐。



















