GMTC全球大前端技术大会(北京站)门票9折特惠截至本周五,点击立减¥480 了解详情
写点什么

怎样安全地关闭老旧的 API?

2021 年 3 月 04 日

怎样安全地关闭老旧的API?

本文最初发表于HTTP Toolkit网站,经原作者 Tim Perry 授权由 InfoQ 中文站翻译分享。


万物都会有终结,HTTP API 也不例外。不论你的 API 今天看上去多么伟大,迟早有一天你会想发布一个全新的版本,新版本能更好地解决相同问题,在各方面可能都会有所改善,但是它因为有了新参数,与旧版本也无法兼容,或者你只是想彻底关闭旧的 API。总而言之,你现在的 API 不会永远存在。


但是,这并非轻而易举就能完成的,因为你的 API 有客户端。如果你关闭端点、参数或整个 API 而没有做出恰当的警告的话,那他们肯定会非常不爽。


那么,该怎样安全地关闭 API,让你的用户尽可能地感到轻松愉快呢?


在这方面,我们有正确的做事方式,包括两个新的头信息草案,它们正在被新的 IETF “Building Blocks for HTTP APIs”工作组进行标准化,旨在形成一个精确的过程。我们了解一下。

制定计划

初始第一步:检查相关的 API 是否真的有客户端。


希望你能有某些 API 的度量指标,至少在某些地方存有日志。如果没有的话,那把它们添加上,如果你有这些东西的话,并且你能确定没有人再使用这个 API 了,那么恭喜你,你赢了。现在,你就可以把它关掉,删掉代码,不要再管这篇文章了,好好睡一觉。


下一个问题,如果比较遗憾,你无法去睡觉的话,那就要问问自己,除了关闭这个 API,还有没有其他方案。你关闭的所有东西都有可能破坏别人的代码,并且会消耗他们的时间来修复这些问题。如果 API 能继续运行的话,对客户端的生态系统和整个 web 的健康都是有好处的。


在很多场景下,旧的 API 可以在内部进行转换,透明地转化成对新 API 的调用,这样可以避免维护两个完全独立的版本。这是Stripe的API版本管理方式的一个基本组成部分,他们在所有发生变化的 API 中都包含了转换,以确保对不兼容的旧版本 API 的请求能继续像以前那样运行,根据需要自动转换请求和响应从而可以使用较新的代码。


这样的转换并不总是可行的,而且如果永远这样做的话会带来明显的额外复杂性,但是如果你可以做到这一点的话,就能为用户提供非常有价值的稳定性,并且可以节省大量废弃旧版本或维护旧版本相关的工作。


但是,如果这个服务/端点/参数已经用到了生产环境,而且继续支持它是不现实的做法,那么它必须要被淘汰。


要实现这一点,我们就要有一个计划。我们首先要问自己三个关键的问题:


  • 你希望用户该怎么做?常见的答案包括:

  • 升级到相关功能的一个更新的、依然能得到支持的版本

  • 使用一些可替代的端点/参数/服务

  • 使用不同的服务,它们与你无关,不需要你关心

  • 用户应该何时迁离这个 API?你所提出的替代方案现在就可以用了吗?

  • 截止时间是什么时候?也就是,这个 API 何时会完全停止使用?(如果不能完全确定的话,你可以稍微延迟回答这个问题)。


计划准备就绪之后,我们就该把它告诉人们了。

沟通

首先,要把这一决定告诉人们。


发邮件到邮件列表,在 Twitter 或微博上发帖,如果有 API 规范的话,对其进行更新(比如,OpenAPI 在operationsparameters上有一个deprecated字段),并在相关的在线文档上大声强调这一点。


你应该包含上文提到的所有信息:他们应该做些什么作为替代方案,你建议他们什么时候开始迁移以及他们必须要进行迁移的最后期限(如果已经确定期限的话)。


在将这些信息告诉给人们后,接下来就该告诉计算机,而这就是新的 IETF 头信息可以发挥作用的地方。

Deprecation 头信息

Deprecation头信息能告诉客户端请求的资源现在依然像以前那样运行,但是这种方式已经不再推荐使用了。通过一个简单的 HTTP 头信息,我们就可以声明这一点:


Deprecation: true
复制代码


另外,我们还能提供一个日期。这个日期告诉用户他们何时该开始进行迁移。这个日期可以是一个过去时间(这代表他们应该立即开始迁移),也能是将来时间(通常这意味着他们要迁移到的新环境还没有准备就绪)。如下所示:


Deprecation: Thu, 21 Jan 2021 23:59:59 GMT
复制代码


如果你要废弃整个端点或服务,那么你可以在每个响应中都带上这样的头信息。如果你想要废弃的是一个具体的特性,可能是一个参数、请求方法或者请求体中的某个特定字段的话,那么你应该在该特性被使用的时候才在响应中包含这个头信息。


为了给客户端更多的信息,我们还可以使用Link HTTP 响应头信息链接至端点或人类易读的文档。在同一个Link头信息中,我们可以包含多个这样的链接,只需要使用逗号进行分割即可(后面我们会看到一个完整的例子)。该规范定义了四个与 API 废弃相关的链接:

Deprecation 链接

我们可以为 deprecation 链接指向一个人类易于阅读的描述:


Link: <https://developer.example.com/deprecation>; rel="deprecation"; type="text/html"
复制代码


这是告诉用户发生了什么以及他们该怎么办的主要方式。你应该始终使用它。如果还没有完整的详情和最终的关闭日期,那么即使只是一个占位符,这也是很有帮助的。在这种情况下,不要忘记让用户订阅更新,这可以采用邮件列表、RSS 或其他类似的方式来实现。

Latest-Version 链接

如果你希望客户端转移至 API 相同端点的最新版本,那么可以使用该链接指向它,如下所示:


Link: <https://api.example.com/v10/customers>; rel="latest-version"
复制代码

Successor-Version 链接

如果你的 API 有多个可用的版本,通常最好每次向前迁移一个版本,而不是直接从最老的、现已废弃的版本跳到最新的版本。为了帮助解决这个问题,我们链接至已废弃版本的下一个版本,而不是最新版本,如下所示:


Link: <https://api.example.com/v2/customers>; rel="successor-version"
复制代码

Alternate 链接

如果该 API 没有新的等价版本,用户最好迁移到一个完全不同的资源,它可能是一个很好的替代方案,那么我们使用 alternate 链接来指明这一点,如下所示:


Link: <https://api.example.com/v2/users/123/clients>; rel="alternate"
复制代码

Sunset 头信息

如果你知道了 API 何时完全关闭的话,那么就应该添加一个Sunset头信息


Sunset 头信息告诉客户端 API 何时会停止运行。这是一个强制的截止时间:API 客户端必须要在这个日期前进行迁移,我们承诺在这个时间前不会破坏任何事情。


在这里,我们必须要提供一个时间,它应该是一个未来的时间。不过,如果它是一个过去的时间,这也是可以的:此时就相当于说“这个 API 会在任意时刻关闭,你需要立即停止使用它”。它如下所示:


Sunset: Tue, 20 Jul 2021 23:59:59 GMT
复制代码


这非常简单,它不仅可以用到 API 关闭的场景中:我们能用它来标记将来 URL 迁移的 HTTP 重定向,或者表明特定 URL 有限的生命周期(适用于临时性的内容,或者适用于具有监管要求的特定资源,比如数据保留策略)。它所说明的就是“这个端点可能在该日期后不会再按照你的预期运行,请做好准备”。

Sunset 链接

该规范也提供了一个 Sunset 链接的关系。按照设计,它会链接至关于关闭特定端点更加详细的信息(如果你有 deprecation 链接的话,它们可能会是同一个)或者关于服务的通用 Sunset 策略。如下所示:


Link: <http://developer.example.com/our-sunset-policy>;rel="sunset";type="text/html"
复制代码


在这里我们也要指出,通用的 Sunset 策略是非常有用的!Sunset 策略会告诉客户端,当我们关闭端点的时候(比如,一年后替代方案上线),用户该如何确保他们能得知这一情况(邮件列表、状态页面、HTTP 头信息等)以及他们通常应该做些什么(更新、检查文档、遵从Link头信息)。


如果马上就要废弃某个 API 的话,添加这样的链接作用其实不大,但是如果你能在一年前就将其发布出去的话,你的客户端可能已经为此做好了准备。


除此之外,发布 Sunset/Deprecation 策略的最好时间就是现在。如果你恰好正以某种方式编写 Deprecation 文档的话,这么做是值得考虑的。

组合到一起

按照设计,这些组成部分能很好地协作。例如,为了表明某个最近废弃的 API,该 API 会在 6 个月内彻底关闭,我们要链接至文档并提供下一个版本的直接链接,那么我们应该在响应中包含如下的头信息链接:


Deprecation: Thu, 21 Jan 2021 23:59:59 GMTSunset: Tue, 20 Jul 2021 23:59:59 GMTLink: <https://api.example.com/v2/customers>; rel="successor-version",    <https://developer.example.com/shutting-down-customers-v1>; rel="deprecation"
复制代码

渐进式关闭

如果所有这些都已经准备到位,并且 sunset 截止时间已过,那么我们就可以将 API 关闭了。


但是,这并不意味着你需要立即且彻底消灭该 API。渐进式关闭能有助于确保任何使用该 API 的所有客户端都有最后的机会在它彻底消失前得到最后一次警告。GitHub 在 2018 年移除一些加密支持的时候曾经这样做:首先禁用一个小时,然后启用它,最后在两周后彻底禁用了它。


这里还有另外一个技巧:安卓在 2015 年为已废弃的原生API增加了越来越多的延迟,在彻底关闭 API 前,最终达到了 16 秒的等待。


这些渐进式的关闭为那些错过截止日期的客户端提供了一些灵活性,并且能帮助那些没有注意到废弃时间点的客户端,从而能在 API 彻底关闭之前处理一些问题。

谨慎行事

不管采用哪种方式,只要你尽了最大的努力去沟通关于 API 关闭的事情,那么现在就可以关闭端点/特性/整个服务,删除代码,然后睡个好觉。


像这样小心谨慎地进行废弃和关闭,可以让你的客户端尽可能清楚地知道他们该如何依赖你的 API,何时需要采取行动,以及他们需要做什么。这种变更可能是一件大事儿,这些信息是很重要的。


这些新的草案头信息让我们不仅可以与人类沟通,还能将这些信息暴露给自动化系统。随着这些头信息的普及,我很高兴地开始看到有更多的工具建立在它们之上。通用的 HTTP 客户端可以根据这些数据自动记录有用的警告日志,API 生成器本身也能根据 API 规范处理越来越多的问题,而 HTTP 调试器(如HTTP Toolkit)可以在截获的实时流量中为你突出显示废弃端点的使用。这是一个令人激动的时刻,我们可以开始安全地关闭 API 了!


需要注意的是,这些头信息是 HTTP 规范的草案。在最终确定前,它们有可能会发生变化。也就是说,它们经历了几轮修改,从现在开始,它们不太可能发生巨大的变化,现在能广泛测试它们了。


不过这也意味着还有时间进行反馈! 如果你对它们的工作方式和如何更好地运行有想法的话,请与“Building Blocks for HTTP APIs”工作组联系。你可以给邮件列表发邮件:httpapi@ietf.org,或者在这里查看之前的邮件列表讨论。


原文链接:


https://httptoolkit.tech/blog/how-to-turn-off-your-old-apis/

2021 年 3 月 04 日 15:421699
用户头像
张卫滨 业精于勤,行成于思。

发布了 379 篇内容, 共 218.2 次阅读, 收获喜欢 324 次。

关注

评论

发布
暂无评论
发现更多内容

5G 和云原生时代的技术下半场,视频化是最大最新的确定性

阿里巴巴云原生

人工智能 云原生 5G 存储 调度

大数据作业的工作流调度详解

大数据技术指南

大数据 4月日更

软件测试面试题【2021模拟面试整理版(含答案)】

程序员一凡

面试 软件测试

学会 Java 数据结构,想不飘都难

学Java关注我

Java 编程 架构 程序人生 计算机

Impala简介以及与Hive的异同

五分钟学大数据

4月日更 impala

大牛荐书 | 百度技术大牛都在读的7本书!

百度开发者中心

开放原子超级链动态内核上线,十分钟可搭建一条区块链

百度开发者中心

Linux后台开发面试总结

赖猫

面试官:什么是死锁?怎么排查死锁?怎么避免死锁?

互联网架构师小马

Java 面试 死锁

三次给你讲清楚Redis之Redis是个啥

华为云开发者社区

数据库 nosql redis hash 字符串

架构可视化支撑系统演进探索

华为云开发者社区

架构 软件系统 架构可视化 辅助系统 架构可视化辅助系统

超硬核!非科班学生拿下字节跳动offer,只因这份算法笔记

互联网架构师小马

Java 字节跳动 数据结构 面试 算法

2021年金三银四最新美团、字节、阿里、腾讯Java面经,已拿offer!

Java架构之路

Java 程序员 架构 面试 编程语言

万万没想到!师兄给我的JVM笔记才是拿下阿里offer的致胜法宝

互联网架构师小马

Java 面试 JVM jvm调优

为什么 MySQL 不推荐使用 join?

互联网架构师小马

Java MySQL join

一不小心,它成为了 GitHub Alibaba Group 下 Star 最多的开源项目

阿里巴巴云原生

Java 微服务 云原生 dubbo Arthas

Apache-Flume的安装及简单应用

慢慢de

win10 flume 日志采集

HugeGraph图数据库获Apache TinkerPop官方认证

百度开发者中心

CMS垃圾收集器

张sir

Java JVM 垃圾收集

终于有腾讯架构师把困扰我多年的《计算机网络原理》全部讲明白了

云流

Java 架构 网络 计算机 程序员·

Canalys发布2020 Q4中国云市场报告

百度大脑

百度 AI

工作中的设计模式 —— 策略模式

程序员小航

Java 设计模式

神级操作:他凭借“Java核心技能精讲”,竟收割了21个Offer

互联网架构师小马

Java 编程 程序员 面试 软件开发

月薪30K以上的C/C++Linux后台服务器开发学习路线是怎样的?

赖猫

c++ Linux 后台开发 后端

San介绍以及在百度APP的实践

百度开发者中心

github访问速度很慢-一招完美解决,小伙伴们赶快get起来吧!

再见孙悟空

GitHub github访问 github打开慢 github.com github打不开

三年Java程序员成功跳槽涨薪,这份《阿里巴巴金三银四Java高级面试题》给了我很大的帮助。

Java架构之路

Java 程序员 架构 面试 编程语言

用AI实践继续探索2050全面数字乡村建设

百度大脑

AI

「开源」首次被列入“十四五”规划,未来大有可为

百度开发者中心

5年crud经验,三个月啃透888页Java王者级核心宝典,竟翻身阿里p6

Crud的程序员

Java 编程 架构 java面试 Java工程师

mysql事务隔离的研究

硬核编程

怎样安全地关闭老旧的API?-InfoQ