直接echo json_encode()出错的根本原因是php输出流被污染且未设置响应头,正确做法是统一使用封装的response()函数并严格控制输出时机与格式。

为什么直接 echo json_encode() 总是出错
因为没控制输出时机和响应头,前端拿到的常是 text/html 类型或混入了调试信息。常见现象包括:fetch 解析失败、Unexpected token 、Vue 的 <code>data 字段突然变成字符串而非对象。
根本原因不是 JSON 写得不对,而是 PHP 输出流被污染——比如在 echo json_encode() 前已有空格、BOM 或 var_dump(),或者之后还有代码执行。
- 必须在输出前调用
header('Content-Type: application/json; charset=utf-8') -
echo后必须接exit或die,不能只return - 避免在框架视图层、模板文件里拼 JSON,统一收口到逻辑层
-
CLI环境下禁止调用header(),需提前判断PHP_SAPI !== 'cli'
怎么写一个真正可用的全局 response() 函数
PHP 没有内置的统一响应函数,得自己封装。最稳妥的方式是定义一个全局函数,放在项目启动时自动加载的文件里(比如 bootstrap.php 或 functions.php),而不是塞进某个类里——否则控制器里还得 use 或 new,反而增加调用成本。
函数签名建议为 response($data, $message = '', $code = 0, $http_status = 200),其中 $code 是业务码(如 1001),$http_status 是真实 HTTP 状态码(如 401)。
-
$http_status直接透传给http_response_code(),不转换、不映射 - 对
$data做类型预检:若为resource、mysqli_result或未实现JsonSerializable的对象,抛出明确异常,例如Cannot JSON encode resource #7 - 不自动映射状态码文案,
$message必须由调用方传入,避免硬编码导致多语言或定制化失效 - 敏感字段脱敏(如
password)是 Controller 层该干的事,response()只负责干净地输出
ThinkPHP 项目里怎么真正统一所有出口
ThinkPHP 的 API 响应格式无法靠改一个配置或重写 json() 就搞定——因为 return json($data)、异常抛出、验证失败、success()/error() 方法,走的是完全不同的响应生成路径。必须分层拦截。
- 重写
think\response\Json类,只重写output($data)方法,把原始数据包进标准结构:['code' => $this->code, 'message' => $this->message, 'data' => $data] - 用中间件兜底所有非
Json响应:检查$response instanceof \think\Response且不是Json实例;若响应体是数组(如异常默认结构),提取['code', 'message', 'data'];否则统一包装为['code' => 500, 'message' => 'server error', 'data' => null] - 用 Trait 封装
success()/error(),但底层必须走你重写的Json类或中间件,否则只是假统一 - 注册中间件为全局,确保它在
ResponseTrace之后、输出之前执行
所有错误分支都必须走同一个 response() 出口
很多人给 success 写了封装,却在 catch 里手写 echo json_encode(['code'=>500]),结果格式不一致、状态码错位、甚至漏设 header。正确做法是:所有分支都走 response(),只是参数不同。
- 正常流程:
response($user, '获取成功', 0, 200) - 参数错误:
response([], '用户名不能为空', 4001, 400) - 服务异常:
response([], '数据库连接失败', 5001, 500) - 不要在
catch里调http_response_code(500)后再echo,直接交给response()统一发
复杂点在于:中间件、异常处理器、验证失败钩子、CLI 脚本入口,都要各自判断是否跳过 header() 和 exit();最容易被忽略的是 ThinkPHP 的 ValidateException 默认走 HTML 响应,不经过任何 JSON 封装逻辑——这得靠中间件强行拦截重写。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











