应用接口版本兼容设计和使用原则

2023-10-27

背景

由于不同版本的升级与APP的客户端的升级是一致的,所以接口就不能像web一样能实时更新,代码可以每次拉取都不同,因为接口更新就应该遵守连续性原则

几个版本解释

在项目开发过程中,为了不同的目的,我们会出现很多版本管控,对于新人来说,有时候是很乱的

代码版本

这个是给产品用的,产品在管控产品实现进度时,都会有一个清晰的版本,这也是大家最熟悉的,一般用 4 位数定,第 1 位是架构层面的,使用上会大变样,后台设计重构等才会变动,2 位是大功能版本,也即一个新的功能,是一个新方向,3 位是小功能,也即已定方向下功能的追加,4 位是各版本上线后会遇到一些 bug 和小优化

发布版本

  1.  对前后端分离的 web 开发,才有这个概念,因为前端和后端并非同时发布,所以具有两套代码,两套代码就有两套版本,但针对 web 来说,两者可以共用一个代码版本号,不需要发布版本概念,采用的方式就是交替增加版本号,无论是服务端发布还是前端发布都是在原来的代码版本上加 1,一起发也是加 1,所以叫交替加 1

  2. 对于类应用(chrome extension 和小程序)来说,发版即推送,速度很快,但是上线有审核期,所以和服务端代码版本开始出现偏离,在审核期间,服务端也可能又迭代了新的版本,这样就不能实现 web 的交叉+1,单独维系比较好,但类应用因为升级速度很快,老旧版本不多,并且还是静默升级,只需要发布版本和代码版本一致即可

  3. 应用版本(App 和 Desktop)因为是安装在用户的手机或者电脑上,版本参差不齐,这就有版本提醒功能,应用商店的版本号经过调研,基本采用 3 位号,来提醒用户需要升级,例如 Mac 的 App Store,这个提醒还是挺重要的,对于安卓手机来说,Google Play 和国内的小米市场、360 软件管家,都会有升级提醒,这个可以有效提醒用户升级,为了抓住这个点,那么就出现了 发布版本 的概念

接口版本

  1. 早期开发时,由于选型架构等问题,老旧接口仍然要正常运行,需要逐步引导客户使用新版,但是接口由新团队进行开发,比如 PHP 转成了用 Go 来开发,响应更快,并发更大,新的接口又和老的接口逻辑相近,但传入传出都不相同,这种巨大差异,不应该在原版接口中改动,容易产生灾难性的影响,因此,我们会在 url 上进行处理,例如 url 中接口版本为/api/v1,等到新接口采用/api/v2,这样就有效的改善了新版用户的无缝衔接,接口版本非常少,如果公司接口版本搞得很多,绝对出问题了

用户数据兼容——升级接口

  1. 用户升级的点在于新旧版本的不同,会导致数据库结构的变化,旧用户不升级无影响,升级后,因为数据库中需要填充一些默认数据,才能支持应用端的加载,如果采用数据库批量实例化,升级几百万用户数据库会很卡,数据量会暴增,但百万用户中有多少僵尸用户并不能判断,所以让用户在升级版本后进行升级是最节省成本的

  2. 用户升级依据的版本应该是应用的 发布版本 ,服务端会有分界线版本号(比如 1.3.4,1.4.0,1.4.3,1.5.0 注意分界线版本号并不连续,并非每次迭代版本都要升级数据库)以及与分界线版本号对应的升级逻辑(代码层面用动态函数进行处理),升级完成后会记录在数据库,避免多台设备导致的重复升级的问题。

升级遵守的连续性规则

  1. 当一个用户从旧版本直接升级到新版本时,为了保证该用户的信息能满足最新接口的需要,需要做一些数据更新,但数据库数据是按版本号逐步更新的,就如Django的数据库迁移原则一样,本次迁移依赖于上次迁移,上次迁移依赖于上上次迁移,这种连续性依赖被称为连续性规则

分界线版本的产生

  1. 在接口开发过程中,会出现一些版本分界线(例如 1.1.3 版本为分界线),同一个接口在 1.1.3 之前返回错误码为 300001,之后返回的为 300001 - 300003 ,这种拆分是为了丰富提示性,给用户带来更精确的提醒,但是 1.1.3 之前不兼容 300002-300003,就会导致报错,造成旧用户的困扰,此时 1.1.3 就是一个分界线版本,此时的分界线版本号并没有数据库层级的升级,因此不会被放到数据库升级分界线版本号列表中去,而会被添加到中间件版本号中处理。

  2. 另外一种就是 request 传入参数和 response 传出参数差异也会出现分界线版本号;

  3. 分界线版本号的出现,采用 函数名_1_1_3 这种命名方式,通过动态地获取 header 中的 version 号,找到最近匹配的那个接口执行并返回结果,这个可以写成装饰器或者注解方式来自动化处理;

    1. 动态函数的好处,就是不需要用无限的 if...elseif 进行判断

代码版本 VS 接口版本再回顾

  1. 代码版本和接口版本不是一个概念,代码版本是每次代码功能的迭代和升级,且代码版本可能会触发多个版本接口的更新;

  2. 接口版本是因为客户端的结构变了,导致的传入参数变动,比如传入参数废弃,新增,以及改变名称导致,原接口无法识别和接收,所以新增了接口版本来兼容该客户端;

  3. 代码版本一般为v1.3.6.x 这种,接口版本为v1/v2

  4. 新增接口,不会导致接口版本变更,同理删除接口也不会导致接口版本变更,因此在没有任何必要的情况下,不要对接口进行变更,使用新增接口的方式来取代旧接口,除非旧接口是完全有问题的,必须得改,才开新版本接口,header 层面开发,一般用中间件根据版本分界线进行处理。

  5. 总结:

    1. 一般不会有接口版本,除非是破坏性的改造,原来的接口都会推翻,用新的路由进行区分,保持新旧接口都能用;

    2. 大部分是对代码版本的兼容,代码版本是有分界线的,例如上面的 1.3.6 前和后,这个分界线,需要调整用户的数据存储结构,扩充新版本的功能,比如旧版没有用户信息,新版需要展现用户信息,但有些数据没有就要默认存入,如果批量存入,面对百万级用户时,是一个很耗时的事情,采用谁升级谁补充的方式,将大大节约性能,这时就需要在用户登录时,补一些默认数据进去,这时 1.3.6 就是一个分界线了

数据表字段的变更增删改查

  1. 字段名修改:不到万不得已,数据表字段名坚决不能更改,即使发现是错的,也要一错到底,同理数据表名也是,因为所有的系统都遵守连续性原则,一旦改名意味着从上到下的修改,所以数据表名和字段的命名,要充分思考后才定,不能疏忽,特此提醒!!!

  2. 字段名新增:新增字段,会涉及到旧接口版本逻辑中,不填充该字段,如果该字段在早期版本中能获取,则视情况调整接口补充,但非必要情况下,不要动旧版本的任何逻辑,避免造成的不可预知的问题发生;

  3. 字段名删除:这个操作是灾难性,一旦旧版本中引用到该字段,该字段名被删除后,将牵涉一堆逻辑的修改,不到万不得已,不要删除字段

    1. 采用冗余方式,就放在那里,或者开新表,后期难以维护这时,再重构,开新坑!!

接口必要原则

针对类App的开发,因为App本身能够存储数据,且App本质的速度相应比网页版快,这里快的其中之一就是网络请求Api接口时间节省,如果能避免频繁的请求接口,就能提高用户使用体验,本地数据缓存的重要性就显得尤为重要。

  1. 对于低数据量的用户数据,都应该存储在用户本地,例如1万以下数据量,避免频繁向服务端请求;

  2. 对于立刻渲染的数据,也可以延迟同步发送到服务端,避免每次操作后,重新拉取服务端的数据。

  3. 所有的API请求应该走一个队列,采用触发机制来触发,在系统启动后触发,更新时触发,每次调用接口时触发队列进行发送。

  4. 对于插件开发来说,应该有个定时器,定时向服务端发送,例如1s一次进行同步,这样能保证本地限流,也能保证数据不争抢,同时也能满足数据的同步需求。

  5. 数据的状态应该保存在本地,用户的每次操作应该以本地的数据为主,除非一些频繁更新的核心数据,才实时从服务端拉取。

  6. 也即应该以做游戏的思维,只将必要的数据操作,结果性的数据同步到服务端,过程中的数据不进行同步,对实时性要求不高的数据也不实时同步。

具体实现

  1. 如果是从v130升级到v140的话,中间缺少了很多版本,那么 v130 应该调用最近的 v131 版本,执行完毕后,再执行 v134 版本,注意 v131 和 v 134 并不一定间隔着 v132 和 v133,因为版本分界线只在需要升级的时候才会有,所以不是每个版本都有, 直到最后执行 v140,这个程序实现私时会用到动态函数调用,如何执行动态函数不同代码有不同实现;

  2. 面对降级之后的处理?检测到该用户已经升级过最新版,则强制要求该用户升级到最新版,来使用最新版的接口,如果强制使用,那会造成新功能数据的丢失。

  3. 数据库迁移脚本应该统一由git来控制版本,在测试环境数据来回测试通过后,将该脚本提交到git版本去,然后由指定人员进行审核后,在生产环境中执行。

  4. 新版接口测试通过后要向前兼容两个版本的Api接口测试,确保向上的兼容性

  5. 每迭代我版本,即第三版上线时,可以清理上两个版本的之前的数据表字段和,避免有些表字段随着版本迭代,出现不断冗余的问题。造成后期人员无法维护。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

应用接口版本兼容设计和使用原则 的相关文章

随机推荐

  • 图像格式互转

    一 灰度图转YUV 由于工作需要 经常接触12bit灰度数据 因此在这里将数据的处理记录下来 经常接触的是sensor输出的12bit灰度数据 按照需求经常会将这份数据转换成其他格式 如16bit灰度数据 高4bit为0 YUV数据等 其中
  • asio(十一)、udp异步服务器

    官网教程 https think async com Asio asio 1 26 0 doc asio tutorial tutdaytime6 html udp异步服务器 int main try 创建一个服务器对象来接受传入的客户端请
  • MaxCompute实例相关操作

    通过MaxCompute提交的SQL Spark和MapReduce等作业会实例化 以MaxCompute实例 Instance 的形式存在 MaxCompute实例有对应的实例ID 实例ID永久有效 且全局唯一 查看实例信息 查看实例信息
  • 检查蓝牙是否连接

    检查蓝牙是否连接 private BroadcastReceiver mBlueToothReceiver new BroadcastReceiver Override public void onReceive Context conte
  • npm用法及离线安装方法

    npm用法及离线安装方法 基本的用法 查看某个模块的全部信息 或者可以查看单个信息 npm info name npm info name version npm info name homepage install支持多种手段 包名 gi
  • 图像分类&图像检索

    图像检索 基于深度学习的图片检索 图像检索 指基于内容的图像检索 即以图搜图 则是给定一幅查询图像 搜索与之相似 视觉或语义上 的图像 图像检索一般是提取图像特征后直接基于相似性 距离 度量标准计算查询图特征和数据库中图像特征之间的相似性
  • 学习笔记(三)基于FPGA的频率计

    1 原理 主要是通过两个计数器 在系统时钟下对高低电平保持时间计数 来实现计算输入信号的频率和占空比 2 Verilog代码 频率计 module freq cnt input clk input rst n input signal in
  • Hexo 字数和阅读时间统计插件

    项目地址 链接 hexo symbols count time 安装配置 安装插件 npm install hexo symbols count time save 在站点配置文件 config yml 中添加以下代码 symbols co
  • i686和x86_64的区别

    i686的解释 i代表intel系列的cpu 386 几乎适用于所有的 x86 平台 不论是旧的 pentum 或者是新的 pentum IV 与 K7 系列的 CPU等等 都可以正常的工作 那个 i 指的是 Intel 兼容的 CPU 的
  • c语言中,关于延迟函数的理解

    对于延迟 有些c基础的人都能够做到用for或while来实现 例如 include
  • Postern + Charles + Burpsuite 进行对 APP 进行抓包

    Postern Charles Burpsuite 进行对 APP 进行抓包 一 简单介绍 二 配置环境 三 配置 Charles 四 配置 postern 五 配置 Charles Burpsuite 六 Charles 和 Fiddle
  • STM32与ST-LINK/V2报错的解决方法

    追加阅读 STM32与ST LINK V2报错的解决方法 2 今天到入手了一块STM32F103C8T6最小系统版 想烧录点程序进去 发现keil5软件偶尔能检测到板子 大多数时候会报一堆错误 串口更是找不到 遇见的问题包括但不限于 ST
  • 【Qt】利用Tool Button控件创建下拉菜单按钮

    功能描述 利用qt进行界面设计和开发 创建下拉按钮 详细实现 1 在qt侧工具栏利用设计打开 ui文件 2 创建按钮 创建一个Tool Button按钮 并在属性窗口中的QToolButton栏中选中MenuButtonPopup属性 3
  • [从零开始学DeepFaceLab-3]: 使用-开发环境准备

    目录 1 GPU环境 1 1 安装N卡驱动程序 2 Python环境 2 1 安装Anaconda 2 2 安装tensorflow 2 3 GPU库的安装
  • linux用less查看文件内容,Linux文件内容查看 - less命令

    查看nohup out文件的内容 大于10万行 显示行号 显法读取文件的百分比 行号及总行数 root li384 34 data grainger images less NM nohup out 1 Searching for imag
  • MyBatis插入时获取自增id

    关于MyBatis在插入时获取自增id 1 1 注释方法 Insert insert into book bid bname price number cratedate values null bname price number cra
  • Netty网络编程(三):Channel详解

    文章目录 简介 Channel详解 异步IO和ChannelFuture Channel的层级结构 释放资源 事件处理 总结 简介 Channel是连接ByteBuf和Event的桥梁 netty中的Channel提供了统一的API 通过这
  • SpringBoot -ElasticSearch RestHighLevelClient 高级客户端使用(1) 初始化

    此处使用ElasticSearch6 4 2版本 SpringBoot 和ElasticSearch 环境以及 安装ik分词等操作不再缀诉 直接进入整合 本节不阐述原理 导入依赖 此处使用的elasticsearch为6 4 2版本 Spr
  • mdk5.14无法烧录

    mdk无法烧录 报错信息 Full Chip Erase Done No Algorithm found for 08000000H 080019E7H Programming skipped Error Flash Download fa
  • 应用接口版本兼容设计和使用原则

    背景 由于不同版本的升级与APP的客户端的升级是一致的 所以接口就不能像web一样能实时更新 代码可以每次拉取都不同 因为接口更新就应该遵守连续性原则 几个版本解释 在项目开发过程中 为了不同的目的 我们会出现很多版本管控 对于新人来说 有