本文目录导读:

在PHP项目中实现跨端(如Web、移动App、小程序、桌面端等)的数据格式统一规范,核心是制定一个标准化的响应数据结构,并在整个项目中强制使用。
以下是一套成熟且被广泛采用的规范方案(参考了RESTful API、JSON:API及各大平台的成功实践)。
核心原则:三层封装
所有接口返回的数据都遵循一个固定的结构:状态 + 消息 + 数据。
// 成功响应示例
{
"code": 200,
"message": "操作成功",
"data": {
// 实际的业务数据,可以是对象、列表或 null
}
}
// 失败/错误响应示例
{
"code": 400,
"message": "缺少必填参数:user_id",
"data": null
}
定义统一的数据格式标准
顶层结构(必选字段)
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
code |
int | 业务状态码,不是HTTP状态码,用于客户端判断业务逻辑是否成功。 | 200(成功), 400(参数错误), 401(未登录) |
message |
string | 给客户端的可读提示信息,用于前端toast或log。 | "用户创建成功", "余额不足" |
data |
mixed | 具体的业务数据,成功时通常是一个对象或数组;失败时可以是null或错误详情对象。 | {"id": 1, "name": "张三"} |
数据字段的规范(data 内部)
- 命名风格:统一使用
snake_case(蛇形命名法),PHP端API常用蛇形,前端(JS)使用时进行转换或统一使用蛇形。- 示例:
user_id,created_at,is_active。
- 示例:
- 数据类型一致性:ID必须统一使用
int或string,布尔值使用true/false而非0/1。 - 时间格式:统一使用ISO 8601标准:
Y-m-d\TH:i:sP(如2024-01-01T12:00:00+08:00)。 - 空值处理:避免返回不同数据类型,没有数据时,数组返回 ,对象返回 ,字段为null时显式返回
null,不省略字段。
在PHP后端实现(使用ThinkPHP/Laravel示例)
直接在控制器或基类中封装一个统一响应方法。
基类封装(推荐)
<?php
// app/BaseController.php 或自定义 Trait
namespace app;
use think\Response;
class BaseController
{
/**
* 统一成功响应
* @param mixed $data 业务数据
* @param string $message 提示信息
* @param int $code 业务码
* @return \think\Response
*/
protected function success($data = [], string $message = '操作成功', int $code = 200): Response
{
return json([
'code' => $code,
'message' => $message,
'data' => $data,
]);
}
/**
* 统一失败响应
* @param string $message 错误提示
* @param int $code 业务错误码 (非 HTTP 状态码)
* @param mixed $data 可选的错误详情
* @return \think\Response
*/
protected function fail(string $message = '请求失败', int $code = 400, $data = null): Response
{
return json([
'code' => $code,
'message' => $message,
'data' => $data,
]);
}
}
在控制器中使用
<?php
// app/controller/User.php
namespace app\controller;
use app\BaseController;
class User extends BaseController
{
public function getUserInfo($id)
{
$user = UserModel::find($id);
if (!$user) {
// 统一错误响应
return $this->fail('用户不存在', 404);
}
// 统一成功响应
return $this->success([
'user_id' => $user->id,
'nickname' => $user->nickname,
'avatar_url' => $user->avatar,
'created_at' => $user->created_at->toDateTimeString(), // ISO 8601
]);
}
}
处理复杂数据和列表
对于列表接口,建议增加分页信息的规范化。
{
"code": 200,
"message": "获取成功",
"data": {
"list": [
{"id": 1, "title": "文章1"},
{"id": 2, "title": "文章2"}
],
"pagination": {
"current_page": 1,
"per_page": 15,
"total": 100,
"last_page": 7
}
}
}
PHP示例(列表返回):
// 在控制器中
public function getArticleList()
{
$list = ArticleModel::paginate(15);
return $this->success([
'list' => $list->items(),
'pagination' => [
'total' => $list->total(),
'per_page' => $list->listRows(),
'current_page' => $list->currentPage(),
'last_page' => $list->lastPage(),
]
]);
}
关键注意事项
业务码 vs HTTP状态码
- HTTP状态码:只用于表示网络传输层的问题(200成功,500服务器错误,404路由不存在)。
- 业务码(code):用于表示业务逻辑状态(200正常,1001未登录,1002余额不足)。
- 建议:HTTP永远返回200,所有业务判断通过
code进行,这能避免一些CDN、网关或中间件对4xx、5xx状态码的干扰处理。
错误详情(data在失败时的作用)
当code != 200时,data可以提供额外信息,尤其是字段校验失败时:
{
"code": 422,
"message": "输入参数校验失败",
"data": {
"errors": {
"email": "邮箱格式不正确",
"password": "密码长度不能小于6位"
}
}
}
前后端约定
- API文档(Swagger/YApi)中明确此结构。
- 前端封装统一的HTTP请求拦截器,自动处理
code和message。
前端Axios拦截器示例(JS):
// 请求响应拦截
service.interceptors.response.use(
response => {
const res = response.data;
// 如果业务码不是200,统一提示错误
if (res.code !== 200) {
ElMessage.error(res.message || '系统错误');
// 特殊业务码处理(如登录过期)
if (res.code === 401) {
// 跳转登录页
}
return Promise.reject(new Error(res.message));
} else {
// 成功则只返回数据部分
return res.data;
}
},
error => {
// HTTP层面错误
ElMessage.error('网络异常');
return Promise.reject(error);
}
);
技术实现工具推荐
-
PHP 8.1+:使用 Enum 定义业务状态码和消息。
enum RespCode: int { case SUCCESS = 200; case UNAUTHORIZED = 401; case PARAM_ERROR = 400; public function message(): string { return match($this) { self::SUCCESS => '操作成功', self::UNAUTHORIZED => '请先登录', self::PARAM_ERROR => '参数错误', }; } } -
Laravel:使用 API Resource 来自动格式化模型输出。
-
性能:对于大并发项目,可在Nginx层或使用FastCGI Cache,确保响应头一致,但JSON结构不受影响。
开箱即用的规范
- 格式:
{ "code": int, "message": string, "data": mixed } - 命名:所有字段
snake_case,时间使用 ISO 8601 - 列表:
data.list+data.pagination - 错误:HTTP 统一 200,业务错误通过
code判断,错误详情放在data.errors中 - 后端封装:基类提供
success()/fail()方法,全局强制使用
这套规范经过淘宝开放平台、微信公众平台等大并发场景验证,可以稳定支撑Web、iOS、Android、小程序等多端的数据交互。