跳到主要内容

协议变更和蓝绿发布

在开发新版本接口时,经常会出现协议的变更,这会重新生成 ServiceProto 然后同步到客户端项目。 这里牵扯出重要的一个问题:新生成的 ServiceProto 与旧的能保持兼容吗? 如果贸然更新服务端,是否会引发旧版协议客户端的异常?

通常有几种情况。

类型兼容的情况

新协议的在类型层面兼容旧协议,这种情况下新旧协议是兼容的,可以无缝切换,例如:

旧协议
export interface ReqSubmit {
name: string
}

export interface ResSubmit {
id: number
}
新协议
export interface ReqSubmit {
name: string,
age?: number
}

export interface ResSubmit {
id: number,
time: Date
}
  • 新协议的请求虽然多了一个 age 字段,但由于是可选的,所以旧版协议的请求也能够兼容
  • 新协议的响应虽然多了一个 time 字段,对于旧版协议它是一个多余字段,会被自动剔除

类型不兼容的情况

例如:

旧协议
export interface ReqSubmit {
name: string
}

export interface ResSubmit {
id: number
}
新协议
export interface ReqSubmit {
name: string,
age: number
}

export interface ResSubmit {
newId: number
}
  • 新协议的请求多了必需的 age 字段,如此旧协议的请求便会收到 “缺少必需字段 age” 的报错
  • 新协议的响应缺少了旧协议必需的 id 字段,如此旧协议的响应便会收到 “缺少必需字段 id ”的报错

这种情况下新旧协议类型不兼容,如果贸然更新服务端版本,可能导致旧协议的客户端出现报错。

这种情况下,也有一些解决方案,例如:

  • 旧接口不变,而是写一个新的接口 Submit_1,如此就变成了类型兼容的情况,可以无缝切换
  • 蓝绿发布

蓝绿发布

无论哪种情况,你都可以使用蓝绿发布来避免因协议变更导致的问题。

  1. 先发布服务端,发布到不同的 URL 下
    • 例如旧版 /api/v1/,新版 /api/v2/
  2. 再发布客户端,客户端切换到新版 URL
  3. 发布完成后,等待一段时间,再弃用旧版接口
    • 因为可能仍有部分用户停留在旧版应用中没有刷新

已知问题

如果你新增的字段中包含了索引签名,例如:

// 旧协议
export interface ResXXX {
a: string
}

// 新协议
export interface ResXXX {
a: string,
b: { [key: string]: number }
}

此时可能由于编码机制原因,导致旧协议的客户端无法兼容。 这个问题出现概率极小,会在 TSRPC 4.0 中解决。 目前,你可以通过把新字段类型改为 any 临时解决:

// 新协议
export interface ResXXX {
a: string,
b: any
}

当然,还是更推荐使用 万能的蓝绿发布