Skip to content

废弃策略与迁移

基于 HTTP/REST 工程实践 · RFC 8594 (Sunset) · 核于 2026-08

速查

  • 废弃(Deprecation)≠ 删除:旧版本/字段不能直接删,要先标记废弃给迁移窗口,到期才下线。直接删会让客户端崩溃(违反 API 稳定性承诺)。
  • 废弃通知机制:①**Deprecation 头**(RFC 并非标准但广泛用,Deprecation: true 或日期);②**Sunset 头**(RFC 8594,Sunset: Wed, 11 Nov 2026 00:00:00 GMT 明确退役日期);③响应体 deprecation 字段;④文档/OpenAPI spec 标记;⑤GraphQL @deprecated 指令(schema 层,客户端 IDE 显示删除线)。
  • Sunset 头(RFC 8594):HTTP 响应头,明确告诉客户端「这个资源/版本将在何时退役」。客户端可据此主动迁移,而不是某天突然收到 410。是废弃通知的标准做法。
  • 迁移窗口(Migration Window):从标记废弃到真正下线的时间(通常 6-12 个月,长尾场景更长)。窗口期新旧版本并存,客户端有时间迁移。窗口长度取决于客户端数量和迁移难度。
  • 向后兼容原则(减少升版本频率):①只加字段不减;②只放宽不收紧;③新增可选参数;④改实现不改契约;⑤想改名时「保留旧字段 + 加新字段」给过渡期。
  • 替代方案要清晰:废弃通知必须说明「用什么替代」「怎么迁移」——文档链接、新字段名、代码示例。光说「废弃了」不说怎么迁移是不负责任的。
  • 下线(Sunset/Retirement):到期后旧版本返回 410 Gone(区别于 404,明确「永久移除别再试」)+ 升级指引 body。监控旧版本流量,接近 0 才下线;有长尾客户端要再延长窗口或保留最小适配。

一、废弃的生命周期

一个 API 版本/字段的完整生命周期:

活跃(Active)
  ↓ 发生破坏性变更需求
标记废弃(Deprecated)  ← 新版本上线,旧版本标记废弃,给迁移窗口
  ↓ 持续监控 + 客户端迁移(6-12 个月)
退役(Sunset/Retired)  ← 旧版本返回 410 Gone,正式下线
  • 标记废弃不是立即删除:废弃后旧版本仍正常工作(客户端不挂),只是开始倒计时。
  • 退役(Sunset)才真正下线:到期后旧版本不再服务,返回 410 Gone。
  • 窗口期监控:持续监控旧版本流量,若仍有大量客户端未迁移,要延长窗口或主动联系(对 B2B API)。

二、废弃通知机制

2.1 Sunset 头(RFC 8594)—— 标准

http
HTTP/1.1 200 OK
Sunset: Wed, 11 Nov 2026 00:00:00 GMT
Deprecation: true
Link: <https://api.example.com/v2/users>; rel="successor-version"
  • Sunset:RFC 8594 定义的标准头,明确「何时退役」(HTTP 日期格式)。客户端可据此规划迁移。
  • Deprecation:标记「已废弃」(虽未成为正式 RFC 但广泛使用)。
  • Link 头 rel="successor-version":指向新版本,客户端知道迁移到哪。

2.2 响应体字段

json
{
  "data": {...},
  "meta": {
    "deprecation": "此端点已废弃,将于 2026-11-11 下线,请迁移到 /v2/users",
    "sunset": "2026-11-11T00:00:00Z",
    "successor": "https://api.example.com/v2/users"
  }
}

适合需要人类可读说明的场景。

2.3 文档与 spec 标记

  • OpenAPI:用 deprecated: true 标记废弃的 path/operation/field,Swagger UI 显示删除线。
  • GraphQL:用 @deprecated(reason: "...") 指令标记废弃字段,客户端 IDE(如 Apollo)显示删除线和废弃原因。

2.4 监控与告警

  • 日志记录「使用了废弃端点」的客户端,主动联系(对 B2B)或在响应里给个性化迁移提示。
  • 设置废弃端点的调用量告警,流量未下降时延期下线。

三、迁移窗口设计

3.1 窗口长度

场景建议窗口原因
内部 API(团队可控)1-3 个月客户端是内部团队,可协调
B2B API(企业客户)6-12 个月企业客户迭代慢,有大客户绑定
公共 API(海量第三方)12-24 个月长尾客户端多,迁移慢
移动端 API(App)6-12 个月旧版 App 用户升级慢,需保留兼容
  • 过早下线的代价:客户端崩溃、信任流失、口碑下降。
  • 过晚下线的代价:维护成本(多版本共存)、技术债累积。
  • 平衡:基于客户端迁移进度动态调整(监控流量)。

3.2 帮助客户端迁移

  • 详细的迁移文档:变更说明、新旧字段映射、代码示例(curl/SDK 多语言)。
  • 新旧字段并存过渡:想改名(email → emailAddress)时,一段时间内同时返回两个字段(旧字段标记 @deprecated),给客户端迁移期,而非直接改。
  • 渐进收紧:先废弃警告(响应仍正常),再限速(废弃端点限流),最后下线(410)——给客户端「痛感」促进迁移。
  • 沙盒预览:新版本先在 sandbox 环境发布,客户端测试通过后再上线生产。

四、向后兼容原则(减少升版本)

减少废弃与升版本频率的根本是尽量向后兼容

原则做法示例
只加不减新增字段安全,删除破坏avatar 字段,不动旧的
只放宽不收紧必填→可选安全,可选→必填破坏email 从必填改可选
新增可选参数加可选参数安全?fields= 可选
改实现不改契约优化内部不影响客户端换数据库、加缓存
保留旧 + 加新想改名时双字段过渡email + 新 emailAddress 并存
  • 为何重要:每次升 MAJOR 版本(破坏性变更)都增加维护成本(多版本共存)和客户端迁移成本。尽量向后兼容可把这些成本降到最低。
  • 必须破坏时果断升版本:别试图「偷偷改」(改契约不升版本)——这比显式升版本更糟,客户端某天突然崩溃却不知原因。

五、下线(Sunset)的执行

到期退役旧版本:

http
HTTP/1.1 410 Gone
Content-Type: application/problem+json

{
  "type": "https://api.example.com/errors/version-retired",
  "title": "API v1 has been retired",
  "status": 410,
  "detail": "v1 已于 2026-11-11 下线,请迁移到 v2",
  "instance": "https://api.example.com/migration-guide"
}
  • 410 Gone(区别于 404):明确「永久移除,别再请求」,客户端应停止重试并迁移。404 是「不知道有没有」,410 是「曾经有现在永久没了」。
  • 退役前确认流量:监控旧版本调用量,接近 0 才下线;有长尾流量要分析(是僵尸客户端还是重要客户未迁移)。
  • 保留最小适配(极端情况):对极重要的长尾客户(如大企业),可保留一个最小适配层(/v1/ 内部转换到 /v2/),而非完全下线。

交互演示

本叶无专门可视化,废弃与迁移建议结合实际项目(如观察 GitHub API 的废弃公告与 Sunset 头)体会。

下一步

版本控制的策略与生命周期到此讲完。下一步可深入 REST API(版本控制的载体)、GraphQL API(靠 @deprecated 几乎不需版本控制)与 OpenAPI 规范(用 deprecated: true 在 spec 层标记废弃)。