在REST架构中,客户端如何消费超媒体?

4
在学习REST架构时,我注意到在成为RESTful的统一接口约束中,超媒体似乎是一个重要部分;然而,我很难理解基于网络上找到的超媒体定义,客户端如何消费这个超媒体概念。
就我对REST的理解,超媒体基本上是提供给客户端的链接,这些链接包含了资源的表示(因此客户端只需知道REST服务的基本入口点URL)。这些链接实际上是帮助客户端了解其接收到的表示所涉及的选项(例如,如果我请求/children/资源,则可能会收到包含链接到/children/youngest,/children/oldest/,children/create等的XML子列表... 这正是我难以理解的地方... 为什么服务器必须向客户端返回这些“超媒体”链接呢?客户端不应该已经知道这些链接吗?客户端无法自己阅读并正确地跟踪这些链接... 某人必须事先编写客户端代码(例如HTML和/或JavaScript)。如果客户端应该已经知道这些链接,这些链接对客户端有什么好处呢?我错过了什么吗?
5个回答

1
想象一下浏览网页的工作原理。REST非常相似(尽管你实际上在描述相关主题HATEOAS)。意图是您的客户端将检索初始数据,然后有某种方式决定是否请求引用数据。在浏览器中,某些引用(如css、javascript、图像)会立即请求,而其他引用(如hrefs)则仅显示给用户,并且仅在用户选择单击链接时检索。对于您的REST客户端也是如此--基于您的要求,您将自行决定哪些引用自动请求,哪些引用显示给用户进行决策。
如果您有一个显示人员及其地址的应用程序,那么您的应用程序将自动查找人员数据中的地址引用并检索它。如果您的应用程序显示一个人和显示相关数据的选项,那么您将显示该人以及超链接(或类似物),允许用户选择检索和显示地址数据。
问题实际上在于客户端如何可视化所检索到的信息。对此,REST 风格建议允许服务器返回 JavaScript 以动态解析新数据(例如上面我的例子中的地址)。也许返回的数据还包含类似 CSS 的引用以帮助解析,或者包含 JavaScript 链接以允许动态用户交互(听起来有点危险,但是这对于 Web 来说可行)。

如果你向客户端返回整个HTML页面,我可以理解这个链接(超媒体)的意义——你可以使用提供的链接来引导用户从一个页面到另一个页面,并在表示中执行其他功能。但是,如果你只是返回XML/JSON格式的特定信息,例如天气信息,供客户端在其页面的右上角显示,那么我需要考虑超媒体吗? - user1431072
也许吧。在我的安卓手机上,我可以看到天气显示,但如果我点击它,我会得到更多信息,如果我再次点击,我会被发送到天气提供商的页面以获取完整的详细信息。如果您想要这种行为,那么您应该不仅返回当前的天气详情,还应该返回一个链接到更详细的天气报告,并在其中包含一个带有位置参数的主页链接。 - Software Engineer

1
超媒体确实是创建RESTful接口的重要部分。然而,我认为完整的超媒体客户端(有时称为HATEOAS)只是成为更加RESTful的谱系上的一个点。Richardson成熟度模型描述了成为更加RESTful的三个步骤,我发现在考虑采用多少RESTful模式时,这些步骤是很好的指导方针。
在我看来,完整超媒体客户端的最佳示例是Web浏览器。Web浏览器理解HTML 标签表示链接。链接的关键在于用户可以在他们的旅程中“发现”功能。因此,在设计RESTful API时,可以应用相同的原则。
引用:“为什么服务器必须向客户端返回这些‘超媒体’链接?”
因此,一个原因是客户端(如果编写以公开链接)可以使状态转换可发现。
使用链接的另一个好处是您的 API 负责每个链接的结构和数据。因此,服务器端 API 为每个请求生成链接。这意味着服务器 API 可以更改链接的版本或结构而不会破坏客户端。
您可以构建一个没有链接的 RESTful API(Richardson 级别2),但如果您想要更改其中一个 API 请求的 URL 怎么办?您需要实施版本控制策略(通过 url 或标头),或者需要为新功能创建新的 url。随着时间的推移,这可能变得混乱不堪。

Davin,假设我是一家第三方公司,拥有一个简单的HTTP可访问API,为您提供所在城市当前的温度。您是一位移动应用程序开发者,希望使用我的终端/temperature/Boston。以下是这种情况的两个问题:1)我的终端是否是“REST”终端或接近它,如果是,2)在温度表示中,我会向您返回哪些链接? 或者没有吗?如果有,您将如何在移动应用程序中使用它们? - user1431072
1
  1. 如果您遵循RESTful原则设计URL并使用适当的HTTP动词,那么您可以称其为RESTful。
  2. 明天的天气预报链接怎么样?或者下周的呢?或者其他任何信息(如气压或风速)。
- Davin Tryon
如果您有一个简单的服务,通过GET访问,给定特定的URL(例如:http://myweather.com/temperature/f/boston),始终提供波士顿的当前温度,则基本上拥有一个REST服务。 - Software Engineer
有没有什么好的例子可以帮助理解使用jQuery或AngularJS进行客户端开发? - LCJ

1
Fielding在定义统一接口约束时旨在将客户端与服务实现解耦。这与在任何面向对象语言中定义新接口的方法相同。您定义它以将类与其依赖项的实现分离。
为了将客户端与URI结构解耦,您需要在响应中包含具有语义注释和URI的链接。因此,您的客户端可以根据语义注释(例如链接关系相关RDF词汇中的术语)决定要跟随哪个链接。这样,它就不需要知道任何关于URI结构的信息。
您需要将客户端与服务的实现细节解耦,以使它们可重用。最终,您可以创建像Web浏览器一样的通用客户端。不同之处在于,这些客户端将理解它们所做的事情,因此它们不一定依赖于人类。

0

类似这样的东西。

        var discountDetails = new AddDiscountForm()
        {
            promotionId = 123456,
            discountType = "Promotion",
            discount = UnitValue.FromFloat(14.00)
        };

        await journey
            .SelectRoot()
            .SelectRelation("product-finder", new { barcode = "23409-23097" })
            .SelectItem(0)
            .SelectRelation("add-discount", discountDetails)
            .RunAsync();

事实上,我从我的回复中得到了灵感并构建了它。

https://github.com/lukepuplett/surfdude-csharp


0
这些链接对客户端有什么好处呢?如果客户端已经知道它们了,那么它们有什么用呢?
这些链接使状态转换更直接地成为界面的一部分。它们告诉客户端当前状态下是否可以使用这些链接或状态转换(如果不可用,则不出现!)。
如果客户端没有注意到这一点,它可能仍会尝试生成并跟随一个实际上不可用的选项(状态转换)的URL。为了确保避免这种情况,可能需要在双方都复制确定特定状态下可能出现的逻辑。
如果尝试了无效的链接/状态转换,服务器应该报告错误。
另一方面,如果客户端从未允许生成/跟随服务器未提供的链接,它就可以更早地意识到并提供反馈有关问题的情况(通常导致更清晰的情况或错误消息),而服务器应该正确处理无效的请求,即使它没有,这也不会成为问题,因为它很少出现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接