PHP 接口开发规范:统一返回格式、异常处理与参数校验

PHP 接口开发规范:统一返回格式、异常处理与参数校验

在中大型 PHP 项目中,接口的一致性直接决定了前端联调效率、问题排查速度和系统可维护性。很多团队在初期"怎么快怎么写",结果后期陷入"一个接口一种返回格式"的泥潭。

本文将围绕 统一返回格式、全局异常处理、参数校验​ 三大核心,给出一套可落地的 PHP 接口开发规范,适用于 Laravel、ThinkPHP、Hyperf、原生 PHP 等主流框架。


一、为什么需要接口规范?

混乱接口的常见症状:

  • 有的返回 {code:0, data:{}},有的返回 {error_code:200, result:{}}

  • 成功返回 HTTP 200,业务失败却返回 HTTP 500

  • 错误信息一会儿是中文,一会儿是英文

  • 参数错误只返回 "error",没有字段名

  • 异常直接抛给前端,暴露 SQL、路径等敏感信息

后果

  • 前端需要为不同接口写不同解析逻辑

  • 联调成本高,沟通频繁

  • 线上问题难以快速定位


二、统一返回格式规范

1. 标准 JSON 返回结构

推荐使用如下结构:

复制代码
{
    "code": 0,
    "message": "success",
    "data": {},
    "timestamp": 1700000000
}

字段说明

字段 类型 必填 说明
code int 业务状态码(非 HTTP 状态码)
message string 提示信息
data mixed 业务数据(成功时返回)
timestamp int 响应时间戳(秒)

2. 业务状态码设计建议

code 含义
0 成功
400xx 客户端错误(参数、权限等)
40100 未登录
40300 无权限
40400 资源不存在
42200 参数校验失败
500xx 服务端错误
50001 系统异常
50002 数据库异常

⚠️ 注意:code ≠ HTTP 状态码

HTTP 状态码负责传输层语义,code 负责业务语义。


3. 成功返回示例

复制代码
{
    "code": 0,
    "message": "success",
    "data": {
        "id": 1,
        "username": "zhangsan"
    },
    "timestamp": 1700000000
}

空数据统一返回:

复制代码
{
    "code": 0,
    "message": "success",
    "data": {},
    "timestamp": 1700000000
}

4. 失败返回示例

复制代码
{
    "code": 42200,
    "message": "参数校验失败",
    "data": {
        "username": "用户名不能为空"
    },
    "timestamp": 1700000000
}

三、全局异常处理规范

1. 异常分类设计

推荐分层异常体系:

复制代码
Throwable
├── Exception
│   ├── BusinessException      # 业务异常(可预期)
│   ├── ValidateException     # 参数校验异常
│   ├── AuthException         # 认证异常
│   └── SystemException       # 系统异常(不可预期)

2. 自定义业务异常(示例)

复制代码
namespace App\Exceptions;

use RuntimeException;

class BusinessException extends RuntimeException
{
    protected int $code = 50001;

    public function __construct(string $message = '', int $code = 0)
    {
        parent::__construct($message ?: '业务处理失败', $code ?: $this->code);
    }
}

3. 全局异常捕获(以 Laravel 为例)

app/Exceptions/Handler.php

复制代码
public function render($request, Throwable $e)
{
    if ($request->expectsJson()) {
        return $this->handleApiException($e);
    }

    return parent::render($request, $e);
}

protected function handleApiException(Throwable $e)
{
    $code = method_exists($e, 'getCode') ? $e->getCode() : 50000;
    $message = $e->getMessage();

    // 兜底处理
    if ($e instanceof \Error || $e instanceof \TypeError) {
        $code = 50001;
        $message = '系统内部错误';
    }

    return response()->json([
        'code' => $code,
        'message' => $message,
        'data' => [],
        'timestamp' => time(),
    ], $this->getHttpStatus($code));
}

protected function getHttpStatus(int $code): int
{
    return match (true) {
        $code >= 40000 && $code < 50000 => 400,
        default => 500,
    };
}

✅ 好处:

  • 前端无需区分异常类型

  • 敏感错误信息不会泄露

  • 所有接口返回格式一致


4. 异常使用规范

✅ 正确做法:

复制代码
if (!$user) {
    throw new BusinessException('用户不存在', 40400);
}

❌ 错误做法:

复制代码
return json_encode(['error' => 'fail']);

四、参数校验规范

1. 校验原则

  • 所有外部参数必须校验

  • 校验逻辑集中处理,不在 Controller 里写大量 if

  • 校验失败抛异常,不走业务逻辑


2. 基础校验示例(原生 PHP)

复制代码
$data = $_POST;

if (!isset($data['username']) || trim($data['username']) === '') {
    throw new ValidateException('用户名不能为空', 42200);
}

if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
    throw new ValidateException('邮箱格式不正确', 42200);
}

3. Laravel 校验(推荐)

复制代码
public function store(Request $request)
{
    $validated = $request->validate([
        'username' => 'required|string|min:3|max:20',
        'email'    => 'required|email',
        'age'      => 'integer|min:1|max:120',
    ]);

    // 校验通过后直接使用 $validated
}

统一返回格式示例:

复制代码
{
    "code": 42200,
    "message": "参数校验失败",
    "data": {
        "username": "用户名必须为字符串",
        "email": "邮箱格式不正确"
    },
    "timestamp": 1700000000
}

4. ThinkPHP 校验

复制代码
$validate = new \think\Validate([
    'username' => 'require|length:3,20',
    'email'    => 'require|email',
]);

if (!$validate->check($this->request->post())) {
    throw new ValidateException(
        '参数校验失败',
        42200,
        $validate->getError()
    );
}

5. 自定义校验规则

例如:手机号校验

复制代码
Validator::extend('mobile', function ($attribute, $value) {
    return preg_match('/^1[3-9]\d{9}$/', $value);
});

五、Controller 层最佳实践

推荐 Controller 结构

复制代码
class UserController
{
    public function store(UserRequest $request, UserService $service)
    {
        $result = $service->create($request->validated());

        return $this->success($result);
    }

    protected function success($data = [], string $message = 'success')
    {
        return response()->json([
            'code' => 0,
            'message' => $message,
            'data' => $data,
            'timestamp' => time(),
        ]);
    }
}

✅ Controller 只做三件事:

  1. 接收请求

  2. 参数校验

  3. 调用 Service

  4. 返回统一格式


六、HTTP 状态码使用建议

场景 HTTP 状态码 code
成功 200 0
参数错误 400 42200
未登录 401 40100
无权限 403 40300
资源不存在 404 40400
系统异常 500 50001

❗ 不要把业务错误全部返回 200,也不要把系统异常返回 200。


七、接口规范速查表 ✅

项目 规范
返回格式 JSON,统一结构
code 业务状态码,0 表示成功
异常 全局捕获,统一返回
参数校验 集中处理,失败抛异常
Controller 薄层,不写业务逻辑
错误信息 友好、可控、不暴露系统细节

八、总结

一套好的接口规范,核心价值在于:

  • ✅ 前端不再"猜接口"

  • ✅ 后端异常可控、可追踪

  • ✅ 新成员快速上手

  • ✅ 系统长期可维护

接口一致性,不是美观问题,而是工程质量问题。

相关推荐
浮江雾1 小时前
Flutter第十七节-----路由管理(3)
android·开发语言·前端·javascript·flutter·入门
admin and root2 小时前
「移动安全」安卓APP 反编译&frida脱壳技巧分享
android·开发语言·python·web安全·微信小程序·移动安全·攻防演练
踏月的造梦星球2 小时前
DM8 DSC 单机双实例部署
运维·开发语言·数据库
An_s2 小时前
c++对接pdfium(一)win系统篇
开发语言·c++
Zwarwolf2 小时前
Rust零散知识点项目汇总
开发语言·rust
-银雾鸢尾-2 小时前
C#中HashTable相关方法
开发语言·c#
茯苓gao2 小时前
嵌入式开发笔记:Qt信号槽机制深度解析——从原理到实战的全方位指南
开发语言·笔记·嵌入式硬件·qt·学习
ihuyigui2 小时前
海外签收通知短信接口
android·java·开发语言·前端·数据库·后端
雪的季节2 小时前
Python基础5-18
开发语言·python