遇到的情况

本文针对移动互联网客户端需要兼容旧版的情况,强制升级到最新版本的 app 不在讨论之列。

bugtags.com 项目中,我们的版本遵循下面规范。
1.0.1
大功能.小更新.bug 修正
我们的版本列表如下:

1.0、1.1、1.2、1.3、1.4
2.0、2.1、2.2、2.3
3.0、3.1

5.0

这样一个版本结构,所有版本都可以用,跨度最大时,1.0 用户要跟 5.0 用户并存。
以 /api/user/info 接口举例,经过这么多版本的迭代,版本 1.0 跟 3.0 的返回数据结构可能已经完全不同了。
对于这样一个系统,如何设计一个完备的版本架构非常重要。

理解其中的困难

移动互联网,有别于传统的 web 开发。其快速迭代、版本升级与传统的 web 开发相比,有如下困难:

  1. 用户获取困难,留存率低
  2. 客户端升级成本高,部分用户拒绝升级
  3. 多个版本服务器端代码量大,急剧拉高维护成本

架构的目的及要求

  1. 简化版本管理流程,易配置管理
  2. 缩小服务器端的 php 代码规模
  3. 尽量不要引入新的要素

微信群里的讨论

请求形式的约定

  1. 使用域名,如 v1.api.bugtags.com 来区分接口的版本
  2. 将版本信息放到 url 的 pathinfo 中,如 api.bugtags.com/v1/
  3. 将版本信息放到请求参数中,如 api.bugtags.com/user/1?_ver=1.0.1
  4. 将版本信息放到 http header 中,如 API_VER: 1.0.1

版本号用域名是比较不被认同的方案,主要原因是域名管理往往跨部门,增加了沟通成本。
http 头是我个人最赞同的一种方式,可以保持 url 的整洁。
url 参数中携带版本号的方式也很好,但是要注意不要跟业务逻辑的参数名重复。

两种常见的管理代码的方式

git/svn 的 tag 管理方式

优点,随时切换分支成本低,尤其在 git 管理代码时。
缺点,如果多个版本需要修改时,代码合并工作量大。

只有一个分支,在代码中根据版本信息做判断

优点,代码的总体规模小(只有一份代码)
缺点,在需要判断版本的地方会有大量的分支语句

我总结的解决办法

最后的解决办法充分利用了 php 的 autoload 加载机制和命名空间。

  1. 假设 base 是所有业务的基础,是第一个版本,也是生命周期最长的版本。
  2. v10 对版本 1.x.x 提供服务,最大限度消除业务点上的版本逻辑判断,但是不绝对拒绝。
  3. v20/v30 基于 v10 版本开发
  4. v40 版本基于 v30 版本开发

举例说明

v10 提供 a,b,c 三个接口
v20 提供 a1,b,c 三个接口, a1 是 a 的修改
v30 提供 a,b1,c 三个接口, b1 是 b 的修改

用下面三段代码来具体描述

<?php
/**
* View/Api/Base/Config/Config.php
*/
namespace View\Api\Config;
class Config {
function index(){echo __METHOD__;}
}
?>
<?php
/**
* View/Api/V10/Config/Config.php
*/
namespace View\Api\Config;
class Config {
function index(){echo __METHOD__;}
}
?>
<?php
/**
* View/Api/V20/Config/Config.php
*/
namespace View\Api\Config;
class Config {
function index(){echo __METHOD__;}
}
?>

配置版本:

访问版本 代码版本
v10 base
v11 base
v20 v10
v30 v10
  • 基础目录 base 存放大部分公共代码
  • 版本目录 v10/v20 都是版本目录,里面存放此版本与 基础版本不同的逻辑
  • 版本区别以文件为最小粒度,以上面三段代码可以看出。

用户要访问 /api/user/info?ver=3.0.1 此时,类的加载顺序依次为:

  1. 在 v30 下尝试加载 Config.php 失败
  2. 在 v10 下尝试加载 Config.php 失败
  3. 在 Base 下尝试加载 Config.php 成功
  4. 执行相关逻辑

这是限制只能继承一层的原因是尽可能的降低系统的复杂度。这种方式管理代码已经在几个项目中得到一些验证。系统代码的复杂度可以很大程度上降低,尤其是多个版本迭代、又不能强制升级的系统中。另外需要注意的就是 :

  1. 使用这个方式处理加载时,在经过几个版本的沉淀后,应该将通用部分渐渐沉淀到BASE版本中
  2. 发布系统最好带有删除文件功能,否则被部分沉淀后,高版本会依旧使用高版本的代码。

笔者在开发和运营 bugtags.com ,这是一款能够极大的提升 app 开发者测试效率的 SDK 产品,欢迎使用、转发推荐。

PHP 开发的 API 多版本管理实践的更多相关文章

  1. Redis在WEB开发中的应用与实践

    Redis在WEB开发中的应用与实践 一.Redis概述: Redis是一个功能强大.性能高效的开源数据结构服务器,Redis最典型的应用是NoSQL.但事实上Redis除了作为NoSQL数据库使用之 ...

  2. flask开发restful api系列(8)-再谈项目结构

    上一章,我们讲到,怎么用蓝图建造一个好的项目,今天我们继续深入.上一章中,我们所有的接口都写在view.py中,如果几十个,还稍微好管理一点,假如上百个,上千个,怎么找?所有接口堆在一起就显得杂乱无章 ...

  3. [转] 阿里研究员谷朴:API 设计最佳实践的思考

    API是软件系统的核心,而软件系统的复杂度Complexity是大规模软件系统能否成功最重要的因素.但复杂度Complexity并非某一个单独的问题能完全败坏的,而是在系统设计尤其是API设计层面很多 ...

  4. RESTful API 设计最佳实践

    背景 目前互联网上充斥着大量的关于RESTful API(为了方便,以后API和RESTful API 一个意思)如何设计的文章,然而却没有一个"万能"的设计标准:如何鉴权?API ...

  5. ASP.NET Core Web API 开发-RESTful API实现

    ASP.NET Core Web API 开发-RESTful API实现 REST 介绍: 符合REST设计风格的Web API称为RESTful API. 具象状态传输(英文:Representa ...

  6. ****RESTful API 设计最佳实践(APP后端API设计参考典范)

    http://blog.jobbole.com/41233/ 背景 目前互联网上充斥着大量的关于RESTful API(为方便,下文中“RESTful API ”简写为“API”)如何设计的文章,然而 ...

  7. RESTful API 设计最佳实践(转)

    摘要:目前互联网上充斥着大量的关于RESTful API(为了方便,以后API和RESTful API 一个意思)如何设计的文章,然而却没有一个”万能“的设计标准:如何鉴权?API格式如何?你的API ...

  8. RESTful API 设计最佳实践(转)

    背景 目前互联网上充斥着大量的关于RESTful API(为方便,下文中“RESTful API ”简写为“API”)如何设计的文章,然而却没有一个”万能“的设计标准:如何鉴权?API 格式如何?你的 ...

  9. flask开发restful api

    flask开发restful api 如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响.蓝图对restfu ...

随机推荐

  1. MVC模式与三层架构的区别

    之前总是混淆MVC表现模式和三层架构模式,为此记录下. 三层架构和MVC是有明显区别的,MVC应该是展现模式(三个加起来以后才是三层架构中的UI层) 三层架构(3-tier application) ...

  2. iOS开发UI篇—ios应用数据存储方式(归档)

    iOS开发UI篇—ios应用数据存储方式(归档)  一.简单说明 在使用plist进行数据存储和读取,只适用于系统自带的一些常用类型才能用,且必须先获取路径相对麻烦: 偏好设置(将所有的东西都保存在同 ...

  3. c++英文单词频度统计程序

    英文单词频度统计程序(c++版) 写一个程序,分析一个文本文件(英文文章)中各个次出现的频率,并且把频率最高的十个词打印出来. 分析过程: (1)  简单设想大致分为两大步骤: 1.经过文本文件的读操 ...

  4. ViewHolder简洁写法

    ViewHolder holder = null;         if(convertView == null){                 convertView = mInflater.i ...

  5. 转载--JAVA读取文件最佳实践

    1.  前言 Java应用中很常见的一个问题,如何读取jar/war包内和所在路径的配置文件,不同的人根据不同的实践总结出了不同的方案,但其他人应用却会因为环境等的差异发现各种问题,本文则从原理上解释 ...

  6. android技巧(二)listview的优化

    对于listview的优化有以下三个措施: 1.原有listview每一个item显示时都会调用一次getView()方法,实际上对于ListView而言,只需要保留能够显示的最大个数的view即可, ...

  7. IOS第三方字体

    项目中想使用第三方的字体,在stackoverflow上查询解决办法,也折腾一会,添加成功,示例如下: 1.将xx.ttf字体库加入工程里面 2.在工程的xx-Info.plist文件中新添加一行Fo ...

  8. Maven项目的核心pom.xml解释(转)

    文章转自http://blog.sina.com.cn/s/blog_534f69a001010lpv.html maven项目的核心是pom.xml.POM(Project Object Model ...

  9. 【LeetCode】Binary Tree Preorder Traversal

    Binary Tree Preorder Traversal Given a binary tree, return the preorder traversal of its nodes' valu ...

  10. OD调试篇11

    先看看今天这道菜是用什么语言写的 发现是用VC7.0写的,再随便打开看看 发现未注册以及使用限制,那就用OD载入吧 右击查找所有字符串,找unregistered    找到后双击进入 我们会看见一个 ...