三种主流策略
| 策略 | 例子 | 优点 | 缺点 |
|---|---|---|---|
| URL | /v1/users | 直观、易调试、可缓存 | 污染路径 |
| 请求头 | Accept: application/v1+json | URL 干净 | 不可见、难调试 |
| 无版本 | 只增不改 | 最简单 | 改语义就崩 |
关键不在选哪个
真正重要的是弃用流程:先在响应里返回 Deprecation 头,给老版本留够迁移期,再下线;同时保证向后兼容的加法(新字段可选)不破坏旧客户端。
两个坑
- 版本泛滥:每个小改动都开 v 版,维护成本爆炸;
- 不留过渡期:直接删接口等于让调用方半夜故障。
实战案例:三种版本管理翻车
- 不版本化直接改字段:把
userName改名成username,所有老客户端同时报错。破坏性变更必须新旧版本并行,并给足迁移期。 - 长期并行维护太多版本:v1 到 v5 共存,兼容代码越来越重。应明确“支持最近两个大版本”,并公布下线时间表。
- 版本号在 URL、行为却在请求头变:文档与实际不一致,调用方按 URL 判断却拿到不同行为。版本策略必须全站统一且可观察。
常见问题(FAQ)
URL 还是请求头版本更好?URL 更直观、便于调试与缓存,适合多数对外 API;请求头更“干净”但不可见、排障成本高。什么时候需要新版本?删除或重命名字段、改变字段含义、收紧校验等破坏性变更才需要;新增可选字段不必升版本。怎么通知调用方?用 Sunset 响应头声明下线时间,并在文档与控制台同步告警。废弃版本要给多久?给 3–6 个月迁移期,期间监控各版本调用量,确认无流量后再下线。
版本治理的落地机制
策略定下来只是开始,真正决定成败的是配套机制:
- 版本路由集中管理:把版本解析放在网关或统一中间件,业务代码不感知版本号,避免每个接口各写一套判断;
- 调用量可见:按版本打点统计请求量、错误率与调用方分布,下线前必须能回答“还有谁在用”;
- 弃用流程自动化:在响应头返回弃用时间(
Deprecation/Sunset),并在日志中对旧版本调用打标记,便于定向通知; - 契约测试兜底:为每个在用版本保留一组契约测试,防止重构时无意破坏旧版本;
- 文档与代码同源:版本说明由接口定义生成,避免文档写着 v2、实现已经到 v3。
把这五点做齐后,版本下线从“不敢动”变成一次常规发布;缺少任何一项,旧版本往往会长期滞留,最终拖垮维护成本。
与非破坏性演进的配合
减少版本数量最有效的办法,是让尽可能多的变更变成非破坏性的。
- 新增可选字段:优先以新增可选字段的方式扩展能力,而不是修改既有字段的含义。调用方忽略未知字段是应被明确要求的兼容规则。
- 保留已删除字段一段时间:字段下线应分两步:先停止返回但保留文档说明,观察一段时间确认无调用方依赖后再删除声明。
- 用默认值替代必填化:需要收紧校验时,先给出合理默认值让调用方有过渡期,再在下一个版本中改为必填。
- 枚举要有未知分支:新增枚举值会让未更新的调用方解析失败,因此调用方应被要求处理未知值,服务端也应避免删除已有枚举值。
- 变更走评审:把接口定义的改动纳入代码评审,明确标注是否兼容,能在源头拦住大部分破坏性变更。
当非破坏性变更成为默认做法时,版本升级的频率会自然下降,维护成本也随之降低——这比事后管理大量并行版本更省力。