发布于2026-07-07 阅读(0)
扫一扫,手机访问
PHP返回JSON给App的核心是确保App能干净稳定解析,90%问题源于响应头缺失或响应体污染,而非json_encode()错误;必须前置设置header('Content-Type: application/json; charset=utf-8'),校验json_encode()返回值,清除BOM、警告及多余输出,并统一响应结构。

说起PHP给App返回JSON这事儿,大多数人的第一反应就是“用json_encode()转一下不就行了”。但实际项目里,真正让人头疼的往往不是转码本身,而是App那边莫名其妙地报“Invalid JSON”或“Unexpected EOF”,回头一看,响应体居然是空的,或者里面混了一堆乱码和警告信息。可以说,这90%的锅,都甩不到json_encode()头上——问题出在响应头没设对,或者响应体被不知名的东西污染了。
App端,无论是iOS的URLSession还是Android的OkHttp,对响应头的依赖比我们想象的要严格得多。它们需要明确的Content-Type: application/json; charset=utf-8来判断该怎么解码。漏掉这个头、写成text/html,或者只写了application/json忘了charset,结果就是中文乱码,或者解析直接失败——而且这错误还特别隐蔽,你不抓包根本看不出来。
关键操作其实就几行:
header('Content-Type: application/json; charset=utf-8')这行代码,必须在任何echo、print、空白字符、BOM之前执行。别以为放在文件最顶部就万事大吉,如果文件本身带BOM,那BOM字节会先于header输出,直接导致header无效。response()->json()方法。框架帮你自动处理了头信息、编码和状态码,远比手动写header可靠,也不容易出现被中间件覆盖的情况。curl -I看响应头,确认Content-Type正确;再用curl看原始响应体,检查开头有没有空行、Warning信息或者HTML片段——这些都属于“非预期输出”。这个坑踩过的人应该不少。json_encode()在遇到资源句柄(比如PDOStatement)、循环引用对象、非UTF-8字符串、或者INF/NAN这类特殊值时,不会报错,也不会抛异常,而是静默返回false。你接着echo json_encode($data),实际输出的是空字符串,App收到的就是空响应——连个提示都没有。
所以,经验是永远不要直接拿变量去echo,先做一次检查:
$json = json_encode($data, JSON_UNESCAPED_UNICODE); if ($json === false) { error_log('JSON encode failed: ' . json_last_error_msg()); http_response_code(500); echo json_encode(['error' => 'server_error']); exit; }fetchAll(PDO::FETCH_ASSOC)或者mysqli_fetch_all($result, MYSQLI_ASSOC)转成纯数组再说。charset=utf8mb4,并且执行过SET NAMES utf8mb4。不然底层可能是GBK编码,json_encode()一碰到非UTF-8字符就直接罢工了。这个问题最常见,也最容易被忽略。PHP文件开头的BOM、末尾多余的空行和换行、调试时留下的var_dump()、未捕获的警告(比如Undefined index),这些都会在JSON字符串的前后混入不可见字符或者文本。App端一解析,看到JSON开头多了几个字节,直接就崩了。
几个简单但有效的手段:
ob_end_clean()放在json_encode()之前,尤其是当你include了其他文件后,可以避免那些文件里意外输出的空白或HTML干扰。display_errors = Off。不然一个“Undefined index”的警告文字就直接写进响应体了,App根本解析不了。exit($json)这种写法。虽然也能工作,但不够干净。标准做法是http_response_code(200); echo $json; exit;,确保整个响应体只有一段合法的JSON字符串。App端期望的是一份可预测的契约,而不是一个裸的JSON。每次返回都应该包含统一的字段,比如code、msg、data。就算data是空的,也返回一个空数组[],而不是干脆不返回这个字段。否则前端每个接口就要写一套独立的解析逻辑,维护成本很高。
还有几点需要特别注意:
password、token,必须在json_encode()之前用unset()删掉。别指望前端去过滤,后端才是最后一道防线。DATETIME字符串。转成时间戳或者ISO8601标准格式会更通用:date('c', strtotime($row['created_at']))。说到底,最难排查的从来不是什么高深的语法问题,而是那些看不见的BOM字节、一行被遗忘的print_r()、或者数据库连接漏掉了charset参数。它们不会报错,不会提醒你,只是安静地破坏着整个JSON流。所以调试的时候,第一反应不该是“json_encode()怎么写”,而是先去看看——“原始响应体到底长什么样”。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8