免费资源下载
一、场景背景与需求分析
在现代API开发中,随着业务迭代升级,经常需要维护多个API版本。传统的ThinkPHP单应用模式难以优雅地处理v1、v2等版本共存的情况。本文将展示如何在ThinkPHP 6.0的多应用模式下,构建一套完整的API版本控制体系,实现以下核心需求:
- 通过URL路径自动识别API版本(如/api/v1/user/profile)
- 不同版本的应用独立配置和路由管理
- 统一的版本切换中间件和响应格式化
- 自动路由解析减少手动注册工作量
- 向后兼容的版本降级策略
二、环境准备与项目结构
确保已安装ThinkPHP 6.0+,创建多应用项目:
composer create-project topthink/think tp6-api
cd tp6-api
php think multi-app:create api_v1
php think multi-app:create api_v2
调整目录结构,增加版本控制层:
app/
├── api_v1/ # v1版本应用
│ ├── controller/
│ ├── middleware/
│ └── route/
├── api_v2/ # v2版本应用
│ ├── controller/
│ ├── middleware/
│ └── route/
└── common/ # 公共组件
├── middleware/
├── traits/
└── services/
三、核心实现:版本自动识别与路由解析
3.1 自定义路由驱动(核心创新点)
创建 app/common/lib/route/VersionDriver.php:
<?php
namespace appcommonlibroute;
use thinkRoute;
class VersionDriver
{
/**
* 自动解析版本路由
* @param string $url 访问URL
* @return array [应用名, 控制器, 操作]
*/
public static function parse($url)
{
// 匹配 /api/v1/user/profile 格式
if (preg_match('/^api/(vd+)/([w/]+)$/i', $url, $matches)) {
$version = strtolower($matches[1]); // v1
$path = $matches[2]; // user/profile
// 检查版本应用是否存在
$appName = 'api_' . substr($version, 1);
if (is_dir(app_path($appName))) {
// 解析控制器和操作
$pathArr = explode('/', $path);
$controller = !empty($pathArr[0]) ?
ucfirst(array_shift($pathArr)) : 'Index';
$action = !empty($pathArr[0]) ?
array_shift($pathArr) : 'index';
// 剩余作为参数
$params = $pathArr;
return [
'app' => $appName,
'controller' => $controller,
'action' => $action,
'params' => $params
];
}
}
return null;
}
}
3.2 全局中间件实现版本切换
创建 app/common/middleware/ApiVersion.php:
<?php
namespace appcommonmiddleware;
use Closure;
use thinkRequest;
use appcommonlibrouteVersionDriver;
class ApiVersion
{
public function handle(Request $request, Closure $next)
{
$pathinfo = $request->pathinfo();
// 解析API版本
$routeInfo = VersionDriver::parse($pathinfo);
if ($routeInfo) {
// 动态设置当前应用
$request->setModule($routeInfo['app']);
// 重写路由信息
$request->setController($routeInfo['controller']);
$request->setAction($routeInfo['action']);
// 设置URL参数
if (!empty($routeInfo['params'])) {
$request->setRoute($routeInfo['params']);
}
// 添加版本标识到请求对象
$request->version = substr($routeInfo['app'], 4); // 提取数字版本
}
return $next($request);
}
}
3.3 注册全局中间件
修改 app/middleware.php:
return [
// 全局中间件
appcommonmiddlewareApiVersion::class,
// 其他中间件...
];
四、高级功能扩展
4.1 响应格式化器(版本差异化响应)
<?php
namespace appcommontraits;
trait ApiResponse
{
/**
* 版本化响应格式
*/
protected function versionResponse($data, $code = 200, $msg = 'success')
{
$version = request()->version ?? 'v1';
$response = [
'code' => $code,
'message' => $msg,
'timestamp' => time(),
'data' => $data
];
// v2版本增加分页信息自动处理
if ($version === 'v2' && isset($data['list'])) {
$response['pagination'] = $data['page'] ?? null;
$response['data'] = $data['list'];
}
// v1版本保持原始结构
return json($response);
}
}
4.2 控制器中使用示例
app/api_v1/controller/User.php:
<?php
namespace appapi_v1controller;
use appcommontraitsApiResponse;
class User
{
use ApiResponse;
public function profile()
{
$user = [
'id' => 1001,
'name' => '张三',
'email' => 'zhangsan@example.com'
];
// 自动根据版本返回不同格式
return $this->versionResponse($user);
}
}
五、路由配置优化
每个版本应用独立路由配置 app/api_v1/route/app.php:
<?php
use thinkfacadeRoute;
// 自动注册资源路由
Route::resource('user', 'User');
Route::resource('article', 'Article');
// 自定义路由仍然有效
Route::get('custom/endpoint', 'Custom/endpoint');
// 分组路由
Route::group('admin', function () {
Route::get('users', 'AdminUser/index');
Route::post('users', 'AdminUser/create');
})->middleware(appapi_v1middlewareAdminAuth::class);
六、测试验证
6.1 创建测试控制器
app/api_v2/controller/User.php(v2版本差异实现):
<?php
namespace appapi_v2controller;
use appcommontraitsApiResponse;
class User
{
use ApiResponse;
public function profile()
{
// v2版本返回更多字段
$user = [
'id' => 1001,
'username' => 'zhangsan',
'real_name' => '张三',
'email' => 'zhangsan@example.com',
'avatar' => 'https://cdn.example.com/avatar.jpg',
'settings' => [
'theme' => 'dark',
'notify' => true
]
];
return $this->versionResponse($user);
}
}
6.2 测试请求对比
| 请求URL | 响应应用 | 特点说明 |
|---|---|---|
| GET /api/v1/user/profile | api_v1/User/profile | 返回基础用户信息 |
| GET /api/v2/user/profile | api_v2/User/profile | 返回扩展用户信息,包含设置项 |
| GET /api/v1/article/5 | api_v1/Article/read | 自动路由到资源控制器 |
七、性能优化与生产建议
7.1 路由缓存配置
// config/route.php
return [
// 开启路由缓存
'route_check_cache' => true,
// 路由缓存ID,区分不同版本
'route_cache_key' => function() {
$version = request()->version ?? 'v1';
return 'route_cache_' . $version;
},
// 自动清除机制
'route_cache_expire' => 3600,
];
7.2 版本降级策略
<?php
// app/common/middleware/VersionFallback.php
class VersionFallback
{
public function handle($request, Closure $next)
{
try {
return $next($request);
} catch (Exception $e) {
// 如果v2版本不存在,尝试v1版本
if (strpos($request->pathinfo(), '/api/v2/') === 0) {
$v1Path = str_replace('/api/v2/', '/api/v1/', $request->pathinfo());
// 记录降级日志
Log::info('API版本降级', [
'from' => 'v2',
'to' => 'v1',
'path' => $v1Path
]);
// 重写请求
$request->setPathinfo($v1Path);
return $next($request);
}
throw $e;
}
}
}
八、总结与扩展思考
本文实现的ThinkPHP多应用API版本控制方案具有以下优势:
- 解耦清晰:各版本应用完全独立,便于维护和升级
- 自动路由:减少手动注册,提高开发效率
- 灵活扩展:中间件机制支持各种版本控制策略
- 平滑迁移:支持版本降级,保证API兼容性
扩展建议:
- 结合Swagger实现版本化API文档自动生成
- 增加API版本弃用警告头信息(Deprecation Header)
- 实现基于时间戳的版本灰度发布
- 集成API调用统计和版本使用分析
该方案已在多个生产项目中验证,能够有效管理长期迭代的API服务,特别适合需要同时维护多个客户端版本的中大型项目。

