api 接口版本控制找了一下資料總共有幾種類型
- 不設定版本模式意味著每個API只提供一個版本,如果要修改本API, 所有的用戶都必須使用最新的API,任何API的修改都會影響到所有的用戶。
- API自帶版本模式同一個名稱的API可以建立多個版本,API調用方根據自己的需求選擇使用對應的API版本。新版本與老版本共存,意味著老版本用戶不會受新版本更新的影響。
- 兼容性版本模式每個API只有一個版本,API需要兼容以前老版本API的功能。所有版本用戶都調用同一個API,通過內在代碼保證兼容性。
具體一些內容可以看一下介紹https://juejin.im/post/5977f8ba5188255b9a6ad820
解決版本控制有5種類型
1.url增加版本編號
http://localhost/index.php/home/v1/index/test
2.url增加版本信息
http://localhost/index.php/home/index/test/v1
3.新增接口
http://localhost/index.php/home/index/newTest
4.客戶端在做請求的時候在HTTP HEAD里面中添加API-VERSION字段,標識出請求的是哪個接口:
-H "API-VERSION: v1"
-H "API-VERSION: v2"
5.不同版本使用不同的域名,這樣:
v1.api.xxx.com
v2.api.xxx.com
以下代碼是基于TP3.2.3修改的:
用的是第一種url增加版本編號:http://localhost/index.php/home/v1/index/test
修改這個代碼做法是:url可以全部統一修改為最新版本,如果最新版本不存在會自動查找低版本的接口
在網上查找的資料都是可以用那幾種類型,沒有具體事例,下面是我自己想法修改出來的代碼。
修改的tp入口文件名 app.class.php
/**
* 執行應用程序
* @access public
* @return void
*/
static public function exec() {
if(!preg_match('/^[A-Za-z](\/|\w)*$/',CONTROLLER_NAME)){ // 安全檢測
$module = false;
}elseif(C('ACTION_BIND_CLASS')){
// 操作綁定到類:模塊\Controller\控制器\操作
$layer = C('DEFAULT_C_LAYER');
if(is_dir(MODULE_PATH.$layer.'/'.CONTROLLER_NAME)){
$namespace = MODULE_NAME.'\\'.$layer.'\\'.CONTROLLER_NAME.'\\';
}else{
// 空控制器
$namespace = MODULE_NAME.'\\'.$layer.'\\_empty\\';
}
$actionName = strtolower(ACTION_NAME);
if(class_exists($namespace.$actionName)){
$class = $namespace.$actionName;
}elseif(class_exists($namespace.'_empty')){
// 空操作
$class = $namespace.'_empty';
}else{
E(L('_ERROR_ACTION_').':'.ACTION_NAME);
}
$module = new $class;
// 操作綁定到類后 固定執行run入口
$action = 'run';
}else{
//創建控制器實例
/****以下是修改的代碼******/
$p = CONTROLLER_NAME;
$c = explode('/', $p);
$mod = substr($c[0], 0,1);
if ($mod!='V') {
$action = $c[1];
$p = 'V1/'.substr($p, 0,stripos($p,'/'));
}
if (!controller($p)) {
$p = explode('/', $p);
$n = substr($p[0], 1);
$b = 'V'.$n;
while (!controller($b.'/'.$p[1])) {
$n = --$n;
$b = 'V'. $n;
if ($n==0) {
break;
}
if (controller($b.'/'.$p[1])) {
$module = controller($b.'/'.$p[1]);
break;
}
}
}else{
// $module = controller(CONTROLLER_NAME,CONTROLLER_PATH);
$module = controller($p);
$p = explode('/', $p);
$n = substr($p[0], 1);
}
}
if(!$module) {
if('4e5e5d7364f443e28fbf0d3ae744a59a' == CONTROLLER_NAME) {
header("Content-type:image/png");
exit(base64_decode(App::logo()));
}
// 是否定義Empty控制器
$module = A('Empty');
if(!$module){
E(L('_CONTROLLER_NOT_EXIST_').':'.CONTROLLER_NAME);
}
}
// 獲取當前操作名 支持動態路由
if(!isset($action)){
$action = ACTION_NAME.C('ACTION_SUFFIX');
}
try{
self::invokeAction($module,$action);
} catch (\ReflectionException $e) {
// 方法調用發生異常后 引導到__call方法處理
self::isAction($n,$p,$action);
$method = new \ReflectionMethod($module,'__call');
$method->invokeArgs($module,array($action,''));
}
return ;
}
//增加判斷該方法不存在時 查找下一個控制
public static function isAction($n,$p,$action){
if ($n==1) {
$module = controller($b.'/'.$p[1]);
self::isController($module);
try{
self::invokeAction($module,$action);
} catch (\ReflectionException $e) {
// 方法調用發生異常后 引導到__call方法處理
$method = new \ReflectionMethod($module,'__call');
$method->invokeArgs($module,array($action,''));
}
}
$b = 'V'.--$n;
if (controller($b.'/'.$p[1])) {
$module = controller($b.'/'.$p[1]);
try{
self::invokeAction($module,$action);
} catch (\ReflectionException $e) {
// 方法調用發生異常后 引導到__call方法處理
self::isAction($n,$p,$action);
$method = new \ReflectionMethod($module,'__call');
$method->invokeArgs($module,array($action,''));
}
}
self::isAction($n,$p,$action);
}