前言

在app开发中,由于app一旦装入客户端中。那么下次再更新版本的时候后端就不能进行更新,至少在参数获取和接口响应这片段是不能进行更新的。这时候需要对版本进行控制及管理

以往中比较熟悉的app中、及一些终端设备中就必须实现这个控制管理。因为现在由于小程序、和web前后端分离概念的普及,一个小程序的用户单次使用时长以及前后端完全分离的概念,使得用户不用像传统页面中一直跳来跳去。所以小程序、web端的后端逻辑也不得不加入版本控制。否则就会出现用户一个操作由于后端部署新代码出现不可预估的问题,即使在三更半夜部署后端。

前端发送版本

发送本地版本可以通过以下三个方式

  • query string

前端可以通过 query string 来发送版本信息,如下:

url: /user/info?v=1.0.0

  • body

如果是 post 请求可以通过在 body 中发送版本信息

  • header

也可以在请求头中携带版本信息

url: /user/info

header: v = 1.0.0

通常采用一般在 header 请求头中携带,因为一般 query string 和 body 主要是用来发送请求参数。如遇加密等一些需求将会变得稍微麻烦

版本比较代码

基础代码

/**
 * @param v1 {String} 比较的版本
 * @param v2 {String} 被比较的版本
 */
function diffMain(v1, v2) {
  // 将两个版本以点分割
  v1 = v1.split('.');
  v2 = v2.split('.');
  // 获取最长的位数
  let maxLength = Math.max(v1.length, v2.length);
  // 补零
  v1 = v1.concat(new Array(maxLength - v1.length).fill(0)).map(item => Number(item));
  v2 = v2.concat(new Array(maxLength - v2.length).fill(0)).map(item => Number(item));
  // 从左到右比较
  let i = 0;
  while (i < maxLength) {
    if (v1[i] < v2[i]) return '<';
    if (v1[i] > v2[i]) return '>';
    i++;
  }
  return '=';
}

示例

console.log(diffMain('1.0', '1.1'));             // <
console.log(diffMain('2.0', '1.1'));             // >
console.log(diffMain('2.0', '2.0'));             // =
console.log(diffMain('2', '2.0.0.0'));           // =
console.log(diffMain('2.0.0.1.0.1', '2.0.0.1')); // >

范围比较

再创建一个函数用于拿前端发送的版本进行范围比较

/**
 * @param rangeV {Array<String,String>} 版本范围,例如 ['0.0.1', '1.0.0'] 表示从0.0.1至1.0.0之间可匹配。包含0.0.1、但不包括1.0.0
 * @param diff {String} 被对比版本
 */
function vDiff([min = null, max = null], diff) {
  if (
    // vDiff(['*', '*'], '2.0')
    (min === '*' && max === '*')
    // vDiff(['2.0','2.0'], '2.0')
    || (min === diff && max === diff)) {
    return true;
  }

  if (arguments[0].length === 1) {
    // vDiff(['*'], '2.0')
    return min === '*'
      // vDiff(['2.0'], '2.0')
      || diffMain(min, diff) === '=';
  }

  if (min === '*') {
    // vDiff(['*','1.0'], '0.9')
    return diffMain(diff, max) === '<';
  }

  if (max === '*') {
    // vDiff(['1.0','*'], '1.0')
    return diffMain(diff, min) === '='
      // vDiff(['1.0','*'], '2.0')
      || diffMain(diff, min) === '>';
  }

  // vDiff(['1', '1'], '1.0')
  if (diffMain(min, max) === '=') {
    return diffMain(min, diff) === '=';
  }

  // vDiff(['1.0','2.0'], '1.1')
  return (diffMain(diff, min) === '>' || diffMain(diff, min) === '=')
    && (diffMain(diff, max) === '<');
}

示例

  • 基础比较
console.log(diff(['1','2'], '1.2'));             // true
console.log(diff(['1.0','2.0'], '1.2.345'));     // true
console.log(diff(['1.0.0', '2.0.0'], '1.0.2'));  // true
console.log(diff(['1.0.0', '2.0.0'], '0.0.12')); // false
// 包括 1.0.0
console.log(diff(['1.0.0', '2.0.0'], '1.0.0'));  // true
// 不包括 2.0.0
console.log(diff(['1.0.0', '2.0.0'], '2.0.0'));  // false
  • 向下比较
console.log(diff(['*', '2.0.0'], '1.0.2')); // true
console.log(diff(['*', '2.0.0'], '2.0.0')); // false
  • 向上比较
console.log(diff(['1.0.0', '*'], '1.0.2')); // true
console.log(diff(['1.0.0', '*'], '0.2.0')); // false
  • 其他
console.log(diff(['*'], '1.0.2'));                   // true
console.log(diff(['*','*'], '1.0.2'));               // true
console.log(diff(['1.0','2.0'], '1.234'));           // true
console.log(diff(['1.0.0.0','2.0.0.0'], '1'));       // true
console.log(diff(['1.0.0.0','2.0.0.0'], '1.6.7.8')); // true
console.log(diff(['1.0.0.0','2.0.0.0'], '2'));       // false
console.log(diff(['1.0.0.0','1'], '1'));             // true

NodeJS 应用实例

下面使用使用koa进行演示

首先创建一个koa实例

const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
const vDiff = require('version-diff');

app.use(async (ctx, next) => {
  // 接收前端携带的版本信息
  ctx.__v = ctx.request.headers.v || '1.0.0';
  await next();
});

router.get('/', async ctx => {
  await [
    {
      // 匹配到 1.0.0 以上版本逻辑
      v: ['1.0.0', '*'],
      h: async () => {
        ctx.body = {
          v: ctx.__v,
          msg: '1.0.0 > *'
        };
      }
    }
  ].find(item => {
    return vDiff(item.v, ctx.__v);
  }).h();
});

app.use(router.routes());

app.listen(3000);

测试

npm install koa

npm install koa-router

npm install version-diff

node app.js

当前端更新版本时只需要上面所示 第 12 行数组中增加一项即可。例如现在更新1.1.0版本,根据代码比较规则。将原来的 ['1.0.0', '*'] 改成 ['1.0.0', '1.1.0'] 即可,表示匹配 1.0.0 至 1.1.0,但不包括1.1.0。在增加一项 ['1.1.0', '*'] 表示 1.1.0以上。以此类推

router.get('/', async ctx => {
  await [
    {
      // 匹配 `1.0.0` 至 `1.1.0`,但不包括`1.1.0`
      v: ['1.0.0', '1.1.0'],
      h: async () => {
        ctx.body = {
          v: ctx.__v,
          msg: '1.0.0 > *'
        };
      }
    },
    {
      // 匹配到 1.1.0 以上版本逻辑
      v: ['1.1.0', '*'],
      h: async () => {
        ctx.body = {
          v: ctx.__v,
          msg: '1.1.0 > *'
        };
      }
    }
  ].find(item => {
    return vDiff(item.v, ctx.__v);
  }).h();
});

实例代码:https://github.com/8696/version-diff/tree/master/node-demo