本质无区别,json()是response()->json()的快捷函数,均自动设Content-Type并编码;但json()仅在控制器中return才生效,非控制器场景需显式->send()。

控制器里 return json() 和 return response()->json() 有啥区别
没本质区别,json() 是 response()->json() 的快捷函数,底层都走同一套逻辑:自动设 Content-Type: application/json; charset=utf-8,并用 json_encode($data, JSON_UNESCAPED_UNICODE) 编码。但注意:json() 只能在控制器方法中直接 return 才生效;如果在中间件、命令行或钩子中调用,必须显式 ->send(),否则响应体为空。
非控制器场景下 response()->json() 不输出?
是的,这是 ThinkPHP 6+ 的明确设计:响应对象默认只构建,不自动发送。常见现象包括 curl -I 看到 200 但 body 为空、浏览器白屏、Postman 显示 “no response body”。必须手动触发:
-
response()->json(['code'=>0])->send()✅ -
echo response()->json(['code'=>0])->getContent();❌(没发 header,且可能被后续输出干扰) -
response()->raw(json_encode($data))->contentType('application/json; charset=utf-8')->send()✅(但不如直接用json()简洁)
想统一包装所有 JSON 响应结构(比如加 code/msg/data)
不能靠 after 中间件改 $response,因为那时已准备发送,修改无效。正确方式是用 \think\Response::setSendCallback() 拦截真正输出前的瞬间:
- 回调里读原始内容:
$content = $response->getContent() - 仅对
application/json类型处理,避免影响 HTML/下载等其他响应 - 解析后封装:
$newData = ['code'=>0, 'msg'=>'ok', 'data'=>json_decode($content, true) ?: []] - 同步更新
Content-Length头,否则前端可能收不全 - 返回新响应:
return \think\Response::create(json_encode($newData), 'json') - 注册中间件时优先级要高于内置的
JsonResponse,例如在app/middleware.php中写10 => \app\middleware\ResponseWrapper::class
XML 输出报空或 InvalidArgumentException?
ThinkPHP 的 xml() 方法对数据结构敏感,不是所有数组都能转。关键约束:
立即学习“PHP免费学习笔记(深入)”;
- 顶层数组键名必须是合法 XML 标签名:不能数字开头(如
0、123user),不能含空格、冒号、斜杠 - 支持两种结构:一维键值对(
['name'=>'tp', 'url'=>'tp.cn']),或带items键的二维数组(['items'=>[['id'=>1],['id'=>2]]]) - 要指定根节点名:
response()->xml($data, 'users') - 属性需用
@前缀:['@id'=>1, 'name'=>'tp'] - 必须手动设头:
->header('Content-Type', 'application/xml; charset=utf-8'),TP6 不自动补 charset
default_return_type 配置、以及中间件中 setSendCallback 的最终拦截点。三者顺序和作用域错一层,结果就完全不对。**



















