在php项目里实现API多版本控制,核心是让服务端能够识别请求对应的接口版本,再返回对应版本的逻辑处理结果。下面分别介绍基于路由和基于Header的两种实现方案。

一、基于路由的API版本控制实现
路由方式的思路是在接口地址中直接携带版本标识,比如将接口地址设计为/v1/user/info、/v2/user/info的形式,服务端通过解析路由中的版本前缀匹配对应的控制器逻辑。
1. 基础路由解析实现
如果是原生php项目,可以通过解析$_SERVER['REQUEST_URI']获取路由信息,提取版本标识:
<?php
// 获取请求路径
$requestUri = $_SERVER['REQUEST_URI'];
// 解析路径中的版本和接口地址
// 假设请求路径为 /v1/user/info 或 /v2/order/list
$pathInfo = parse_url($requestUri, PHP_URL_PATH);
$pathParts = explode('/', trim($pathInfo, '/'));
// 第一个部分为版本标识,如v1、v2
$version = $pathParts[0] ?? '';
// 剩余部分为接口路径
$apiPath = implode('/', array_slice($pathParts, 1));
// 版本和接口映射表
$versionMap = [
'v1' => [
'user/info' => 'AppControllerV1UserController@getInfo',
'order/list' => 'AppControllerV1OrderController@getList'
],
'v2' => [
'user/info' => 'AppControllerV2UserController@getInfo',
'order/list' => 'AppControllerV2OrderController@getList'
]
];
// 匹配对应的控制器方法
if (isset($versionMap[$version][$apiPath])) {
$handler = $versionMap[$version][$apiPath];
list($controllerClass, $method) = explode('@', $handler);
// 实例化控制器并调用方法
$controller = new $controllerClass();
$controller->$method();
} else {
http_response_code(404);
echo json_encode(['code' => 404, 'msg' => '接口不存在']);
}
?>
2. 框架中的路由配置示例
如果使用Laravel框架,可以直接在路由文件中通过前缀分组管理不同版本的接口:
<?php
// routes/api.php
use IlluminateSupportFacadesRoute;
// v1版本路由组
Route::prefix('v1')->group(function () {
Route::get('/user/info', [AppHttpControllersV1UserController::class, 'getInfo']);
Route::get('/order/list', [AppHttpControllersV1OrderController::class, 'getList']);
});
// v2版本路由组
Route::prefix('v2')->group(function () {
Route::get('/user/info', [AppHttpControllersV2UserController::class, 'getInfo']);
Route::get('/order/list', [AppHttpControllersV2OrderController::class, 'getList']);
});
?>
二、基于Header的API版本控制实现
Header方式不需要修改接口地址,而是在请求的Header中增加自定义字段,比如Api-Version,服务端读取该字段的值判断接口版本,返回对应逻辑的处理结果。
1. 原生php读取Header实现
原生php中可以通过getallheaders函数获取所有请求头,提取版本字段:
<?php
// 获取所有请求头
$headers = getallheaders();
// 读取自定义版本头,默认值为v1
$apiVersion = $headers['Api-Version'] ?? 'v1';
// 接口路径,假设为 /user/info
$apiPath = trim($_SERVER['REQUEST_URI'], '/');
// 版本和接口映射表
$versionMap = [
'v1' => [
'user/info' => 'AppControllerV1UserController@getInfo'
],
'v2' => [
'user/info' => 'AppControllerV2UserController@getInfo'
]
];
// 匹配控制器方法
if (isset($versionMap[$apiVersion][$apiPath])) {
$handler = $versionMap[$apiVersion][$apiPath];
list($controllerClass, $method) = explode('@', $handler);
$controller = new $controllerClass();
$controller->$method();
} else {
http_response_code(404);
echo json_encode(['code' => 404, 'msg' => '接口不存在']);
}
?>
2. 框架中的中间件实现
在Laravel框架中可以通过中间件统一处理版本识别逻辑,避免每个接口都重复读取Header:
<?php
// app/Http/Middleware/ApiVersionMiddleware.php
namespace AppHttpMiddleware;
use Closure;
class ApiVersionMiddleware
{
public function handle($request, Closure $next)
{
// 读取请求头中的Api-Version字段,默认v1
$version = $request->header('Api-Version', 'v1');
// 将版本信息存入请求对象,方便后续控制器使用
$request->attributes->add(['api_version' => $version]);
return $next($request);
}
}
?>
注册中间件后,在控制器中可以直接获取版本信息:
<?php
// app/Http/Controllers/UserController.php
namespace AppHttpControllers;
use IlluminateHttpRequest;
class UserController extends Controller
{
public function getInfo(Request $request)
{
$version = $request->attributes->get('api_version');
if ($version == 'v1') {
// v1版本逻辑
return response()->json(['code' => 0, 'data' => ['name' => 'test', 'age' => 18]]);
} else if ($version == 'v2') {
// v2版本逻辑,新增了手机号字段
return response()->json(['code' => 0, 'data' => ['name' => 'test', 'age' => 18, 'phone' => '13800000000']]);
}
}
}
?>
两种方式的对比与选择
两种实现方式的特点如下,开发者可以根据项目需求选择:
| 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 路由方式 | 版本标识清晰,直接通过地址就能区分,调试方便 | 接口地址会随版本变化,旧客户端需要适配新地址 | 版本差异大,需要长期维护多个独立版本的接口 |
| Header方式 | 接口地址无变化,对客户端无感知,迭代更平滑 | 版本信息隐藏在请求头中,调试时需要额外设置Header | 版本差异小,仅做字段增减或逻辑微调的迭代 |
实际项目中也可以两种方式结合使用,比如对外暴露的接口用Header方式保持地址统一,内部管理接口用路由方式方便区分,满足不同场景的需求。
phpAPI_version_control路由管理Header管理多版本接口修改时间:2026-06-25 11:24:37