API 版本控制基础

版本控制这东西,说起来简单,做起来全是坑。我刚接手公司 API 时,发现十几个服务用着四种不同的版本标注方式——有的在路径里写 v1/v2,有的在 Header 里传 Accept-Version,还有的直接用参数 version=1。每次对接新客户端我都要翻半天文档,那叫一个痛苦。所以这一章咱们把版本号怎么定、怎么传、哪些雷不能踩,一次性说清楚。

版本号语义:SemVer 到底该怎么用

我习惯用 SemVer(语义化版本),格式很简单:MAJOR.MINOR.PATCH。三个数字分别代表:

  • MAJOR:做了不兼容的改动。比如删字段、改必填项、改响应结构。
  • MINOR:新增功能,但向后兼容。比如加了个可选字段。
  • PATCH:修复 bug,内部优化,对外接口没变化。

嗯,但你会发现很多团队把版本号当“发布序号”用,直接跳到大版本——我见过有人把 1.0.0 后直接改成 2.0.0,只因为“重构了一次代码”。这样搞,客户端根本搞不清你到底改了啥。

我的建议:一个版本号只改一个位。如果你同时改了 MAJOR 和 MINOR,那一定是你没想清楚。

举个例子:我曾经维护过一个订单 API,原来返回字段 "price": 100,后来改成返回分单位 "price": 10000。这是 MAJOR 变更,必须升大版本。但我们当时只在路径上加了个 /v2,版本号却还是 1.2.0,导致第三方 SDK 直接跑飞——你说冤不冤?

另外要注意,SemVer 本身并没规定你必须在哪个位置暴露版本号。你可以在 URL 里写 v1.2.3,也可以在 Header 里带个 X-API-Version: 1.2.3。但更常见的做法是只暴露 MAJOR,MINOR 和 PATCH 留给自己跟踪。

版本策略:URL、Header、参数,哪个最靠谱?

现在主流就三种:URL 路径版、请求 Header 版、查询参数版。我画了张图,你看一眼就明白区别了。

API 版本策略对比 URL 路径版 /v2/users Header 版 Accept-Version: 2 查询参数版 ?version=2 优点 • 直观,人人看得懂 • 方便缓存/CDN • 利于不同版本共存 缺点:URL 会变长 优点 • URL 干净 • 适合 RESTful 设计 • 版本降级简单 缺点:难调试/缓存 优点 • 实现简单 • 兼容老客户端 • 动态切换版本 缺点:缓存无效化差

你看,每个策略都有取舍。我个人更倾向 URL 路径版,原因很简单:它能被 CDN、网关、浏览器缓存直接区分,出问题排查时一眼就能看出来是哪个版本。但如果你要保留同一套路由做蓝绿发布或金丝雀,那 Header 版会更干净。

具体怎么选?我列个表

场景 推荐策略 原因
面向公众的 API(B2C) URL 路径 客户端服务端版本解耦,缓存友好
内部微服务间调用 Header 版 避免 URL 膨胀,易于网关统一处理
移动端 API Header 版 + 参数兜底 客户端升级滞后,需服务器端兼容多版本
纯查询类接口 查询参数 前端传递方便,适合轻量场景

不过有一说一,很多团队会混合使用——比如 URL 里写 major 版本号,Header 里传 minor 版本号用于灰度。你想怎么搞都行,但一定要在文档里写清楚。

常见误区,我踩过的坑可不少

误区1:版本号跟着发布日期走。
我曾经有个项目,每个月发一个版本号:2024.01、2024.02……结果半年后调用方代码里全是一堆 /v2024.01/users 和 /v2024.02/users,混乱到没人记得清区别。后来只能全部统一成 SemVer。

误区2:认为向后兼容就不用改版本号。
记得有一次我们加了一个可选字段,但数据库里旧数据没有这个字段,返回时会抛 null。按理说这是 MINOR 变更,但 null 导致客户端崩溃——因为对方用的强类型 SDK。结果还是升了 MAJOR 版本。所以一个原则:你永远不知道客户端怎么消费你的 null,保险起见,只要有可能损坏现有客户端的改动,就升 MAJOR。

误区3:Header 版不需要显式声明。
有些人觉得 Header 里传个 version=2 就够了,但实际上你要在服务端明确返回 X-API-Version: 2 让客户端知道它正在用哪个版本。否则客户端自己猜,就会出大问题。

避坑提醒:我曾经在一个 Header 版 API 里没声明版本响应头,结果某客户端用旧版 SDK 发送了 Accept-Version: 1,但服务端返回了新版数据,因为路由器没把 Header 传给正确的 Handler。从那以后我在每个响应都加了 X-API-Version 头。

误区4:版本 URL 里带三位版本号(1.2.3)。
我理解你想表达精确版本,但在 URL 里写三位非常难维护。客户端无法自动跟随补丁版本,你必须把 /v1.2.3/users 和 /v1.2.4/users 当成两个完全不同的 URL 处理。更好的做法是只用 MAJOR,MINOR 和 PATCH 通过 ETag 或 Last-Modified 跟踪。

总结一下

版本控制说白了就是管理“变化”。你用 SemVer 命名,用合适的策略暴露,再避开那些常见的坑——我心里就踏实了。后面章节咱们会讲到具体怎么用工具做兼容性检测,但基础不牢,地动山摇。这一章的知识点,建议你收藏,写 API 时拿出来对照一下。