【QCon】精华内容上线85%,全面覆盖“人工智能+”的典型案例!>>> 了解详情
写点什么

REST 及其版本控制

  • 2010-06-17
  • 本文字数:2048 字

    阅读完需:约 7 分钟

Ganesh Prasad 最近思考的问题是与 REST 相关的最棘手的问题之一:基于 REST 架构的服务版本控制。Ganesh 通过一个示例说明:

假设有一个资源,它的标识是这样的,“/customers/1234”。人们通过 PUT 修改这个资源的状态。[但是]REST 如何处理 PUT 对应的业务逻辑的变更呢?

因为无法通过修改操作名(如,指定 PUTv2)的方式标识服务的业务逻辑发生的变化,一种可能的做法是修改 PUT 使用的 URL,与此同时维护原有的资源标识,Ganesh 描述到:

如 PUT /customers/v2/1234,这不同于客户端的原有标识 /customers/1234。

该方法类似于 Peter Williams 在几年前谈到,而且其他人甚至在更早就谈到的反模式。Peter 在 2008 年如是说:

我非常痛恨这种方法,其隐含的意思是一个版本的 API 与另一版本的 API 表征不同的资源。它迫使客户端作出进退两难的选择,不是同时支持多版本的 API,就是打破 REST 的核心限制之一。例如,一个 V1 版 API 的客户保存了 URL 引用(该 URL 中包括版本标识),一段时间后客户端更新到新版的 API。 此时,客户端支持该 API 的多个版本,因为所有之前保存的 URI 全部指向旧版本的 API,或者必须要将这些 URI 转接到新版 API。URI 转接打破了 REST 的将多媒体当作应用程序状态引擎(HATEOAS)的限制,而支持多版本的 API 是维护工作中的噩梦。

Peter 建议使用定制媒体类型与(最终必将发生的非向后兼容性变更的)内容协商的结合进行版本控制。

该方法的确会导致新建媒体类型,但是媒体类型是低成本的,所以我们可以,而且应该,需要多少媒体类型就创建多少。如果能正确使用,内容协商可用于解决 REST/HTTP 服务接口的版本控制问题。

但是,回到 Ganesh 以及最初的修改 URL 的方法,他也不同意这种方法。

首先,如果认为只有两处(动词以及资源)可以存放业务逻辑的不同版本,那就是一个错误。第三处是所提交的数据中……但此例仅仅引发了我对版本控制根本的探究。

进而他提出了 REST 与 SOA 所需的版本控制的问题,它问道,首先版本控制是什么,其次为什么需要它?

我认为服务版本控制是一种机制,它使我们能够以消费者可见的方式同时维护两组或多组业务逻辑的版本。

首先他问道,为什么要对消费者可见,如果服务能够区别不同的消费者类型,那么它就能在内部为不同的调用者(客户端 / 消费者)应用不同的业务逻辑?接着它又进一步提出问题:我们为什么要同时维护不同版本的业务逻辑呢?

一个有趣(又迂回)的答案是,业务逻辑通常需要对消费者可见,所以新版的业务逻辑也需要以消费者可见的方式与其旧版本进行区别。这往往被描述成是对旧消费者的支持,比如,消费者在某方面依赖于旧版本的业务逻辑的服务消费者。

支持旧客户的目的是确保现有的契约和 SLA 不会因为服务的(悄然)更新而被破坏。这就引出了 Ganesh 的又一问题,版本控制的问题的解决办法可否不通过使用显式的版本,而在对具体实施细节进行抽象时找到呢?也许服务契约太细节了以至于在变更发生时显得脆弱。(类似于过去 SOA 背后的一个重要原则,松耦合与紧耦合的思想)

Ganesh 接着通过一个例子描述了如何使用这种方法解决版本控制的问题。在该例中,一个虚构的开发人员在已有服务消费者的情况下悄悄地完成了对服务的业务逻辑的变更。

第一个问题是,新的业务逻辑能否应用于所有的消费者,或者我们是否需要跟踪“旧”消费者并继续为他们保留旧的业务逻辑?如果我们能够为所有消费者升级到新的业务逻辑,那是当然没有任何问题的。接口继续保持不变,客户端应用程序将数据 POST 到相同的 URI,请求接着被转发到新建资源的地址……所应用的业务逻辑是全新的,但是客户端不会从接口中感知到变化……

但是,当然也有可能根本无法做到这样,这时就需要维护业务逻辑的多个版本。Ganesh 接着描述了这种情况发生的几个可能的原因:

  • 客户端应用程序应该提交的数据有变化,这种变更不可避免地要让消费者知情,而且不得不使用新契约进行交互。
  • 另一商业原因是区分两类客户,也许是要奖励长期的客户,为他们提供更好的服务,不过该变化不会从客户端提交的数据中察觉出来。
  • 客户端应用程序可能“了解”旧版本的服务行为并依赖于这些行为,这种情况下,需要使用新的版本已避免 d 对遗留客户造成破坏。

Ganesh 认为,第三种情况是人为的,它意味着通过消费者和服务实现之间的显式依赖关系破坏了服务的松耦合性。

相反,第一种和第二种情况都有相应的解决方案。如果由客户端提交的数据要发生改变,那么这本身就是一种区别新消费者与旧消费者的方式,从而可以为他们提供不同的业务逻辑。换言之,我们仅需告诉新消费者他们需要对 POST 的数据作出的修改。旧消费者什么都不用做。此外,如果我们能够在某种程度上得知消费者是旧消费者,那么,即使它既提交的数据没有明显的区别,我们也能透明地应用不同的业务逻辑。

他这样总结自己的观点……

服务的版本不是接口细节,而往往是在接口中泄漏的实现细节。

服务的版本控制问题是许多领域里的常见话题,不仅仅是REST。然而,Ganesh 坚信REST 为该问题提供了更好,更自然的解决方法。


查看英文原文: REST and versioning

2010-06-17 04:484197
用户头像

发布了 184 篇内容, 共 76.3 次阅读, 收获喜欢 7 次。

关注

评论

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

作为一个架构师,我是不是应该有很多职责?

架构师修行之路

程序员 架构师

详解增强算术赋值:“-=”操作是怎么实现的?

Python猫

Python 编程

2020年史诗级‘面试宝典’横空而出,金九银十就靠“它”涨薪了

学习 程序员 面试 架构师

【API进阶之路】用API打造一条自动化内容生产流水线

华为云开发者联盟

自动化 API 部署

Hadoop 简介

yuanhang

hadoop

Nodejs使用es module开发CLI

zayfen

nodejs Module ES cli esm

华为HMS:风雨突然,仍求自我

脑极体

Atlassian Team Tour 9月23日登陆中国,报名通道已开启!

Atlassian

敏捷开发 数字化转型 金融 Jira

通证是下一代互联网数字经济的关键

CECBC

区块链 通证经济

阿里P9开源阿里内部秒杀系统设计方案以及设计原则,还不收藏

小Q

Java 架构 系统设计 秒杀 并发

前端 10 问之 TypeScript (第一篇)

局外人

typescript 大前端

算法与数据中台实践之网约车平台

博文视点Broadview

大数据 数据中台 中台 算法 数据

.NET多线程(Thread,ThreadPool,Task,Async与Await)

AI代笔

flutter在行动之踩坑的日子(1)

霜蓝手环

flutter 跨平台 Flutter Android Apk 编程之路

jvm疯狂吞占内存,罪魁祸首是谁?

易观大数据

易观方舟Open API 及最佳实践

易观大数据

第13周总结+作业

林毋梦

面经手册 · 第10篇《扫盲java.util.Collections工具包,学习排序、二分、洗牌、旋转算法》

小傅哥

Java 数据结构 算法 归并排序 洗牌算法

XSKY全新一代SDS一体机五大场景之超融合

XSKY星辰天合

Hadoop 客户端节点

yuanhang

hadoop3

你不可不知道的Design Thinking

长沙造纸农

设计 思维方式 设计思维 设计实践 设计师

实战解析丨如何对Mysql连接请求的tcpdump内容进行分析

华为云开发者联盟

TCP/IP 数据传输

众盟科技:跨越时空70年,一场别样的房地产直播开启人文探索

人称T客

众盟科技:跨越时空70年,一场别样的房地产直播开启人文探索

脑极体

金九银十:搞定这两个GitHub标星50K开源项目,拿个30k轻松吧?

编程 程序员 面试 算法 架构师

初识大数据

yuanhang

大数据

LeetCode题解:232. 用栈实现队列,使用两个栈 入队 - O(1), 出队 - O(n),JavaScript,详细注释

Lee Chen

大前端 LeetCode

面试官问我:看过sharding-jdbc的源码吗?我吧啦吧啦说了一通!!

冰河

数据库 分布式事务 微服务 分布式数据库 ShardingJDBC

阿里架构师耗时三个月整理的Spring实战笔记:入门到实战

Java架构师迁哥

干货:不同场景容器内获取客户端源IP的方法

华为云开发者联盟

容器 服务端 场景

Hadoop3 环境搭建

yuanhang

REST 及其版本控制_SOA_Mark Little_InfoQ精选文章