Richardson成熟度模型

Posted chenxygx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Richardson成熟度模型相关的知识,希望对你有一定的参考价值。

Richardson成熟度模型

迈向REST的辉煌

一个模型(由Leonard Richardson开发)将REST方法的主要元素分解为三个步骤。这些引入资源,http动词和超媒体控件。

最近我一直在阅读Rest In Practice的草稿技术分享图片:一本我的几位同事一直在研究的书。他们的目标是解释如何使用Restful Web服务来处理企业面临的许多集成问题。本书的核心是网络是大规模可扩展的分布式系统的存在证明,这种系统运行良好,我们可以从中获得创意,更轻松地构建集成系统。

 技术分享图片

为了帮助解释Web风格系统的特定属性,作者使用由Leonard Richardson开发 在QCon演讲中解释的宁静成熟模型 该模型是考虑使用这些技术的好方法,所以我认为我会对自己的解释有所暗示。(这里的协议示例只是说明性的,我不认为值得对它们进行编码和测试,所以细节上可能存在问题。)

0级

该模型的出发点是使用HTTP作为远程交互的传输系统,但不使用Web的任何机制。基本上,你在这里做的是使用HTTP作为你自己的远程交互机制的隧道机制,通常基于远程过程调用

 技术分享图片

假设我想预约与我的医生预约。我的预约软件首先需要知道我的医生在特定日期有哪些空位,因此它会请求医院预约系统获取该信息。在0级情况下,医院将在某个URI处公开服务端点。然后,我向该端点发布一份包含我的请求详细信息的文档。

POST /appointmentService HTTP/1.1
[various other headers]

 服务器然后将返回一个文件给我这个信息

HTTP/1.1 200 OK
[various headers]

<openSlotList>
  <slot start = "1400" end = "1450">
    <doctor id = "mjones"/>
  </slot>
  <slot start = "1600" end = "1650">
    <doctor id = "mjones"/>
  </slot>
</openSlotList>

我在这里使用XML作为示例,但内容实际上可以是任何内容:JSON,YAML,键值对或任何自定义格式。

我的下一步是预约,我可以通过将文档发布到端点再次完成预约。

POST /appointmentService HTTP/1.1
[various other headers]

<appointmentRequest>
  <slot doctor = "mjones" start = "1400" end = "1450"/>
  <patient id = "jsmith"/>
</appointmentRequest>

 如果一切顺利,我会得到一个回复??,说我的预约已被预订。

HTTP/1.1 200 OK
[various headers]

<appointment>
  <slot doctor = "mjones" start = "1400" end = "1450"/>
  <patient id = "jsmith"/>
</appointment>

如果有问题,说别人在我之前进来,那么我会在回复正文中得到某种错误信息。

HTTP/1.1 200 OK
[various headers]

<appointmentRequestFailure>
  <slot doctor = "mjones" start = "1400" end = "1450"/>
  <patient id = "jsmith"/>
  <reason>Slot not available</reason>
</appointmentRequestFailure>

到目前为止,这是一个直接的RPC风格系统。这很简单,因为它只是抛弃普通的旧XML(POX)。如果您使用SOAP或XML-RPC,它基本上是相同的机制,唯一的区别是您将XML消息封装在某种信封中。

1级 - 资源

RMM的休息荣耀的第一步是引入资源。所以现在,我们现在开始与个人资源交谈,而不是将我们的所有请求提交给单一服务端点。

技术分享图片

因此,在我们最初的查询中,我们可能会为给定的医生提供资源。

POST /doctors/mjones HTTP/1.1
[various other headers]

<openSlotRequest date = "2010-01-04"/>

 答复包含相同的基本信息,但是现在每个插槽都是可以单独寻址的资源。

HTTP/1.1 200 OK
[various headers]


<openSlotList>
  <slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
  <slot id = "5678" doctor = "mjones" start = "1600" end = "1650"/>
</openSlotList>

 使用特定的资源预约预约意味着发布到特定的插槽。

POST /slots/1234 HTTP/1.1
[various other headers]

<appointmentRequest>
  <patient id = "jsmith"/>
</appointmentRequest>

 如果一切顺利,我会收到类似的回复。

HTTP/1.1 200 OK
[various headers]

<appointment>
  <slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
  <patient id = "jsmith"/>
</appointment>

现在的区别是,如果任何人需要做任何有关约会的事情,比如预约一些测试,他们首先会得到预约资源,它可能有一个URI http://royalhope.nhs.uk/slots/1234/appointment,并发布到该资源。

对于像我这样的对象,这就像对象身份的概念。我们不是在以太网中调用某个函数并传递参数,而是在一个特定对象上调用一个方法,为其他信息提供参数。

2级 - HTTP动词

我在第0级和第1级使用了HTTP POST动词来处理所有的交互操作,但有些人使用GET或者另外使用GET。在这些级别上,它们没有多大区别,它们都被用作隧道机制,允许您通过HTTP隧道进行交互。级别2远离这一点,尽可能使用HTTP动词以及它们如何用于HTTP本身。

技术分享图片

对于我们的插槽列表,这意味着我们要使用GET。

GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk

 答复和POST一样

HTTP/1.1 200 OK
[various headers]

<openSlotList>
  <slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
  <slot id = "5678" doctor = "mjones" start = "1600" end = "1650"/>
</openSlotList>

在第2级,对这样的请求使用GET至关重要。HTTP将GET定义为安全操作,即它不会对任何状态进行任何重大更改。这使我们可以按任意顺序安全地调用GET,并且每次都可以获得相同的结果。这样做的一个重要结果是,它允许任何参与者路由请求以使用缓存,这是使Web性能与其一样好的关键因素。HTTP包含支持缓存的各种措施,可供所有通信参与者使用。通过遵循HTTP的规则,我们可以利用该功能。

预约一个约会,我们需要一个HTTP动词,改变状态,POST或PUT。我将使用与之前相同的POST。

POST /slots/1234 HTTP/1.1
[various other headers]

<appointmentRequest>
  <patient id = "jsmith"/>
</appointmentRequest>

在这里使用POST和PUT之间的权衡比我想要进入这里更多,也许我会在某一天做一个单独的文章。但我想指出的是,有些人错误地在POST / PUT和创建/更新之间建立了对应关系。他们之间的选择是相当不同的。

即使我使用与第1级相同的帖子,远程服务如何响应还有另一个显着差异。如果一切顺利,服务会回复201的回应代码,以表明世界上有新的资源。

HTTP/1.1 201 Created
Location: slots/1234/appointment
[various headers]

<appointment>
  <slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
  <patient id = "jsmith"/>
</appointment>

201响应包含一个带有URI的位置属性,客户端可以使用该URI来获取将来该资源的当前状态。此处的响应还包括该资源的表示,以便立即保存客户端的额外呼叫。

如果出现问题,还有其他差异,例如其他人预订会话。

HTTP/1.1 409 Conflict
[various headers]

<openSlotList>
  <slot id = "5678" doctor = "mjones" start = "1600" end = "1650"/>
</openSlotList>

此响应的重要部分是使用HTTP响应代码来指示出现问题。在这种情况下,409似乎是一个很好的选择,表明其他人已经以不兼容的方式更新资源。我们没有使用200的返回码,而是包含一个错误响应,我们明确地使用了这种类型的错误响应。协议设计人员需要决定使用哪些代码,但如果出现错误,应该有非2xx响应。2级介绍了使用HTTP动词和HTTP响应代码。

这里存在不一致性。REST倡导者讨论使用所有HTTP动词。他们还通过说REST试图从网络的实际成功中学习来证明他们的方法是合理的。但是世界范围的网络在实践中并不使用PUT或DELETE。有更明智的理由使用PUT和DELETE,但Web的存在证明不是其中之一。

网络存在的关键要素是安全(如GET)和非安全操作之间的强烈分离,以及使用状态代码来帮助传达您遇到的各种错误。

等级3 - 超媒体控制

最后的关卡介绍了你经常听到的HATEOAS(超文本作为应用程序状态引擎)的简称。它解决了如何从列表中开放空位到知道如何做预约的问题。

技术分享图片

我们从我们在第2级发送的相同的初始GET开始

GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk

 但是回应有一个新的元素

HTTP/1.1 200 OK
[various headers]

<openSlotList>
  <slot id = "1234" doctor = "mjones" start = "1400" end = "1450">
     <link rel = "/linkrels/slot/book" 
           uri = "/slots/1234"/>
  </slot>
  <slot id = "5678" doctor = "mjones" start = "1600" end = "1650">
     <link rel = "/linkrels/slot/book" 
           uri = "/slots/5678"/>
  </slot>
</openSlotList>

每个插槽现在都有一个链接元素,其中包含一个URI以告诉我们如何预约约会。

超媒体控件的重点在于它告诉我们接下来可以做什么,以及我们需要操作的资源的URI。我们不需要知道在哪里发布我们的预约请求,反馈中的超媒体控件告诉我们如何去做。

POST会再次复制第2级的内容

POST /slots/1234 HTTP/1.1
[various other headers]

<appointmentRequest>
  <patient id = "jsmith"/>
</appointmentRequest>

并且回复包含许多超媒体控件,用于接下来要做的不同事情。

HTTP/1.1 201 Created
Location: http://royalhope.nhs.uk/slots/1234/appointment
[various headers]

<appointment>
  <slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
  <patient id = "jsmith"/>
  <link rel = "/linkrels/appointment/cancel"
        uri = "/slots/1234/appointment"/>
  <link rel = "/linkrels/appointment/addTest"
        uri = "/slots/1234/appointment/tests"/>
  <link rel = "self"
        uri = "/slots/1234/appointment"/>
  <link rel = "/linkrels/appointment/changeTime"
        uri = "/doctors/mjones/[email protected]=open"/>
  <link rel = "/linkrels/appointment/updateContactInfo"
        uri = "/patients/jsmith/contactInfo"/>
  <link rel = "/linkrels/help"
        uri = "/help/appointment"/>
</appointment>

超媒体控件的一个显而易见的好处是它允许服务器在不中断客户端的情况下更改其URI方案。只要客户端查找“addTest”链接URI,服务器团队就可以处理除初始入口点之外的所有URI。

另一个好处是它可以帮助客户开发人员探索协议。这些链接为客户开发人员提供了接下来可能有哪些可能的提示。它没有提供所有信息:“最新”和“取消”控件都指向相同的URI - 他们需要弄清楚其中一个是GET,另一个是DELETE。但至少它为他们提供了一个出发点,以了解更多信息以及在协议文档中寻找类似的URI。

同样,它允许服务器团队通过在响应中添加新链接来宣传新功能。如果客户开发人员留意未知链接,这些链接可能成为进一步探索的触发器。

关于如何表示超媒体控件没有绝对的标准。我在这里所做的是使用REST in Practice团队的当前建议,该团队遵循ATOM(RFC 4287)。我使用一个<link>具有uri 目标URI属性元素和一个rel属性来描述这种关系。一个众所周知的关系(例如self对元素本身的引用)是裸露的,任何特定于该服务器的关系都是完全限定的URI。ATOM指出,着名链接的定义是链接关系注册表正如我写的,这些仅限于ATOM所做的事情,ATOM通常被认为是3级安宁的领导者。

级别的含义

我应该强调的是,RMM是考虑REST元素的一种好方法,而不是REST本身级别的定义。Roy Fielding已经明确指出,3级RMM是REST的前提条件和软件中的许多术语一样,REST有很多定义,但是由于Roy Fielding提出了这个术语,所以他的定义应该比大多数更重要。

我觉得这个RMM有用的是它提供了一个很好的循序渐进的方式来理解平静思维背后的基本思想。因此,我认为它是帮助我们了解概念的工具,而不是某种评估机制应该使用的东西。我认为我们没有足够的例子可以确定宁静的方法是整合系统的正确方式,但我认为这是一种非常有吸引力的方法,我会在大多数情况下推荐这种方法。

在与伊恩罗宾逊谈这件事时,他强调说,当伦纳德理查森首次提出这个模型时,他发现这种模型具有吸引力的地方在于它与普通设计技术的关系。

  • 1级通过使用分治法解决了处理复杂性的问题,将大型服务端点分解为多个资源。
  • 2级引入了一组标准的动词,以便我们以相同的方式处理类似的情况,消除不必要的变化。
  • 级别3引入了可发现性,提供了一种使协议更加自我记录的方式。

其结果是一个模型,可以帮助我们思考我们想要提供的HTTP服务类型,并构建期望与之交互的人的期望。

 

 

#

以上是关于Richardson成熟度模型的主要内容,如果未能解决你的问题,请参考以下文章

HATEOAS约束

HATEOAS约束

图像修复基于Lucy_Richardson迭代法图像修复matlab源码

Chris Richardson微服务实战系列

Chris Richardson微服务翻译:微服务介绍

Chris Richardson微服务翻译:微服务部署