PHP如何规范生成APP接口并返回JSON格式数据?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1040个文字,预计阅读时间需要5分钟。
PHP 返回 JSON 给 App,核心问题不是怎么转,而是App 能否正确解析、稳定、无歧义地获取并理解数据。90% 的错误(如 Invalid JSON、Unexpected EOF、空响应)都源于响应体被污染或响应头缺失,而非 json_encode() 写错。
必须在输出前设对 Content-Type 和 charset
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 失效 - 用框架(如 Laravel)时,优先用
response()->json(),它自动处理头+编码+状态码,避免手动header()被覆盖 - 调试时用
curl -I http://api.example.com/user看响应头,再用curl http://api.example.com/user看原始响应体——开头不能有空行、Warning:、HTML 片段
json_encode() 返回 false 就是失败,不是“没数据”
json_encode() 遇到资源句柄(如 PDOStatement)、循环引用对象、非 UTF-8 字符串、INF/NAN 值时,静默返回 false,不会报错也不会抛异常。此时 echo json_encode($data) 实际输出的是空字符串,App 收到的就是空响应。
- 务必检查返回值:
$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; } - 数据库查询结果不能直接传给
json_encode():先fetchAll(PDO::FETCH_ASSOC)或mysqli_fetch_all($result, MYSQLI_ASSOC) - 含中文字段来自 MySQL 时,确认连接已设
charset=utf8mb4,且执行过SET NAMES utf8mb4;否则json_encode()可能因 GBK 字节失败
别让意外输出污染响应体
PHP 文件开头的 BOM、结尾的空行、var_dump() 调试语句、未捕获的 PHP 警告(如 Undefined index),都会在 JSON 前/后混入不可见字符或文本,导致 App 解析失败。
立即学习“PHP免费学习笔记(深入)”;
- 用编辑器(如 VS Code、Sublime)保存为 “UTF-8 without BOM” 格式,别信文件名带 “utf8” 就安全
- 输出前清缓冲:
ob_end_clean()放在json_encode()前,尤其在 include 其他文件后 - 生产环境关闭
display_errors = Off,避免警告文字泄露到响应体中 - 不要用
exit($json),改用http_response_code(200); echo $json; exit;,确保只有一段 JSON 字符串
统一结构比“能返回”更重要
App 期望的是可预测的响应契约,不是裸 JSON。每次返回都应包含 code、msg、data 字段,哪怕 data 为空数组,也比直接返回原始数据更可靠。
- 避免在不同接口里有的返回
{'users': [...]},有的返回['a','b'],前端必须写多套解析逻辑 - 敏感字段(如
password、token)必须在json_encode()前unset(),别指望前端过滤 - 时间字段别直接输出 MySQL 的
DATETIME字符串,统一转为时间戳或 ISO8601:date('c', strtotime($row['created_at']))
最难调的从来不是 json_encode() 语法,而是你根本没意识到那三个看不见的 BOM 字节、一行被遗忘的 print_r()、或者数据库连接漏了 charset 参数——它们都在安静地破坏整个 JSON 流。调试时第一反应不该是“JSON 怎么写”,而是“原始响应体到底长什么样”。
本文共计1040个文字,预计阅读时间需要5分钟。
PHP 返回 JSON 给 App,核心问题不是怎么转,而是App 能否正确解析、稳定、无歧义地获取并理解数据。90% 的错误(如 Invalid JSON、Unexpected EOF、空响应)都源于响应体被污染或响应头缺失,而非 json_encode() 写错。
必须在输出前设对 Content-Type 和 charset
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 失效 - 用框架(如 Laravel)时,优先用
response()->json(),它自动处理头+编码+状态码,避免手动header()被覆盖 - 调试时用
curl -I http://api.example.com/user看响应头,再用curl http://api.example.com/user看原始响应体——开头不能有空行、Warning:、HTML 片段
json_encode() 返回 false 就是失败,不是“没数据”
json_encode() 遇到资源句柄(如 PDOStatement)、循环引用对象、非 UTF-8 字符串、INF/NAN 值时,静默返回 false,不会报错也不会抛异常。此时 echo json_encode($data) 实际输出的是空字符串,App 收到的就是空响应。
- 务必检查返回值:
$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; } - 数据库查询结果不能直接传给
json_encode():先fetchAll(PDO::FETCH_ASSOC)或mysqli_fetch_all($result, MYSQLI_ASSOC) - 含中文字段来自 MySQL 时,确认连接已设
charset=utf8mb4,且执行过SET NAMES utf8mb4;否则json_encode()可能因 GBK 字节失败
别让意外输出污染响应体
PHP 文件开头的 BOM、结尾的空行、var_dump() 调试语句、未捕获的 PHP 警告(如 Undefined index),都会在 JSON 前/后混入不可见字符或文本,导致 App 解析失败。
立即学习“PHP免费学习笔记(深入)”;
- 用编辑器(如 VS Code、Sublime)保存为 “UTF-8 without BOM” 格式,别信文件名带 “utf8” 就安全
- 输出前清缓冲:
ob_end_clean()放在json_encode()前,尤其在 include 其他文件后 - 生产环境关闭
display_errors = Off,避免警告文字泄露到响应体中 - 不要用
exit($json),改用http_response_code(200); echo $json; exit;,确保只有一段 JSON 字符串
统一结构比“能返回”更重要
App 期望的是可预测的响应契约,不是裸 JSON。每次返回都应包含 code、msg、data 字段,哪怕 data 为空数组,也比直接返回原始数据更可靠。
- 避免在不同接口里有的返回
{'users': [...]},有的返回['a','b'],前端必须写多套解析逻辑 - 敏感字段(如
password、token)必须在json_encode()前unset(),别指望前端过滤 - 时间字段别直接输出 MySQL 的
DATETIME字符串,统一转为时间戳或 ISO8601:date('c', strtotime($row['created_at']))
最难调的从来不是 json_encode() 语法,而是你根本没意识到那三个看不见的 BOM 字节、一行被遗忘的 print_r()、或者数据库连接漏了 charset 参数——它们都在安静地破坏整个 JSON 流。调试时第一反应不该是“JSON 怎么写”,而是“原始响应体到底长什么样”。

