Stooland API 架构与最佳实践指南
本文档基于 Stooland API 项目的实际代码结构(ThinkPHP 8 多应用模式)以及现代 PHP 开发标准,总结了一套适用于本项目的架构规范与最佳实践。旨在帮助开发团队统一代码风格,提升代码的可维护性、扩展性和安全性。
1. 架构总览
本项目采用 ThinkPHP 8 多应用模式,遵循经典的分层架构设计:
mermaid
graph TD
Request[客户端请求] --> Route[路由层 (route/router.php)]
Route --> Middleware[中间件层 (middleware/)]
Middleware --> Controller[控制器层 (controller/)]
Controller --> Validate[验证层 (validate/)]
Controller --> Service[服务层 (service/)]
Service --> Model[模型层 (model/)]
Service --> ThirdParty[第三方SDK (extend/)]
Model --> Database[(数据库)]核心分层职责
- Controller (控制器): 仅负责 接收请求、参数校验(调用验证器)、调用 Service 处理业务、标准化响应格式。严禁 在控制器中编写复杂的业务逻辑或直接操作数据库。
- Service (服务层): 核心业务逻辑的载体。负责编排业务流程、事务控制、调用 Model 或第三方服务。Service 应该是可复用的。
- Model (模型层): 负责与数据库交互。包含数据表映射、关联关系定义、获取器/修改器、以及数据层面的简单逻辑(如 Scope 查询范围)。
- Validate (验证层): 负责输入数据的格式和规则校验。
- Logic (逻辑层/可选): 对于特别复杂的业务,可以在 Service 之上再抽象一层 Logic,或者作为 Service 的辅助组件。
2. 开发最佳实践
2.1 控制器 (Controller)
- 继承基类: 所有 API 控制器应继承
app\base\controller\ApiBaseController,该基类封装了用户身份认证 (checkLogin)、上下文管理 (getMember,getActor) 和标准响应方法。 - 保持“瘦”控制器: 控制器方法应尽可能简短。
- 参数获取: 使用
$this->getParams('key', $default)获取参数,避免直接使用input()或$_GET/$_POST。 - 标准响应: 必须使用
$this->sendResponse($code, $data, $msg)返回结果,确保前端收到的 JSON 结构一致。
❌ 错误示例:
php
public function create() {
$data = input('post.');
// 业务逻辑混杂在控制器
if ($data['age'] < 18) return json(['code'=>1, 'msg'=>'error']);
Db::name('user')->insert($data); // 直接操作数据库
return json(['code'=>0, 'data'=>'ok']);
}✅ 正确示例:
php
public function create() {
$params = $this->getParams();
// 1. 验证
$this->validate($params, 'User.create');
// 2. 调用服务
$result = $this->userService->createUser($params);
// 3. 响应
return $this->sendResponse(0, $result);
}2.2 服务层 (Service)
- 单一职责: 一个 Service 类应专注于一个领域的业务(如
VolcengineVisualService专注视觉生成)。 - 依赖注入: 推荐在 Service 中实例化 Model 或其他依赖,或者通过构造函数注入。
- 事务管理: 涉及多个数据表更新的操作,务必在 Service 中使用
Db::transaction()。 - 避免直接输出: Service 方法只应返回数据或抛出异常,绝不 应该
echo或return json()。
💡 优化建议: 项目中存在如 VolcengineVisualService::submitTask 这样包含大量 if-else 判断不同 reqKey 的代码。建议使用 策略模式 (Strategy Pattern) 或 工厂模式 进行重构,将每种任务类型的处理逻辑拆分到独立的处理器类中,提高可维护性。
2.3 模型层 (Model)
- 使用 ORM: 优先使用 ThinkPHP 的模型方法(
find,save,create)而非Db::name()->insert(),以便利用模型的自动时间戳、获取器和事件机制。 - 关联关系: 在模型中显式定义关联(
hasOne,hasMany),避免在 Service 中手动拼装关联数据。 - Scope 查询: 将常用的查询条件封装为 Scope(如
scopeActive),提高代码复用性。
2.4 异常处理 (Exception Handling)
- 自定义异常: 业务错误应抛出
app\base\exception\SaasException或其子类,而不是通用的\Exception。 - 全局捕获: 框架的异常处理接管了所有未捕获异常,自动记录日志并返回标准错误 JSON。
- 错误码: 使用
config/status.php(假设) 或常量定义错误码,避免魔术数字。
php
// 抛出业务异常
throw new SaasException(ERROR_Insufficient_BALANCE, '余额不足');2.5 日志 (Logging)
- 使用 Facade: 使用
think\facade\Log进行日志记录。 - 上下文信息: 日志应包含足够的上下文(User ID, Request ID, 关键参数),便于排查问题。
- 分级记录:
Log::info: 关键业务流程节点(如:任务提交成功、支付回调收到)。Log::error: 异常捕获、系统错误、第三方接口调用失败。Log::debug: 调试信息(生产环境通常关闭)。
✅ 推荐写法:
php
Log::info('[Volcengine] Task Submitted', [
'user_id' => $userId,
'task_id' => $taskId,
'params' => $params
]);2.6 安全性 (Security)
- 输入过滤: 信任
ApiBaseController和验证器,但仍需注意 SQL 注入(使用绑定参数/ORM)和 XSS(输出转义)。 - 权限控制: 确保所有敏感接口都进行了
checkLogin或中间件权限校验。 - 敏感数据: 密码、密钥等敏感信息严禁明文记录在日志中(需脱敏处理)。
3. 代码规范
- 遵循 PSR-12: 代码格式遵循 PSR-12 标准。
- 命名规范:
- 类名:
UpperCamelCase(e.g.,VolcengineVisualService) - 方法名:
lowerCamelCase(e.g.,submitTask) - 变量名:
lowerCamelCase(e.g.,userId) - 数据库表名/字段:
snake_case(e.g.,user_id)
- 类名:
- 注释: 核心逻辑、复杂算法和公共方法必须包含 PHPDoc 注释。
4. 目录结构说明
api/app/
├── base/ # 基础模块 (基类、全局异常、中间件)
├── aigc/ # AIGC 业务模块
│ ├── controller/ # 控制器
│ ├── service/ # 业务逻辑
│ ├── model/ # 数据模型
│ ├── validate/ # 验证器
│ └── route/ # 路由定义
├── ... # 其他业务模块
└── extend/ # 扩展类库 (第三方 SDK 封装)本文档由 Stooland 技术团队维护,修订请联系架构组。