HATEOAS:绝对或相对URL?


Answers:


83

当人们说“相对URI”时,存在一个概念上的含糊之处。

根据RFC3986的定义,通用URI包含:

  URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

  hier-part   = "//" authority path-abempty
              / path-absolute
              / path-rootless
              / path-empty

     foo://example.com:8042/over/there?name=ferret#nose
     \_/   \______________/\_________/ \_________/ \__/
      |           |            |            |        |
   scheme     authority       path        query   fragment

棘手的事情是,当省略方案和权限时,“路径”部分本身可以是绝对路径(以开头/)或“无根”相对路径。例子:

  1. 一个绝对URI或一个完整的URI:"http://example.com:8042/over/there?name=ferret"
  2. 这是一个相对uri,具有绝对路径/over/there
  3. 这是一个相对uri,具有相对路径hereor ./hereor ../hereoretc。

因此,如果问题是“服务器是否应在平稳响应中生成相对路径”,则答案为“否”,并且详细原因在此处。我认为大多数反对“相对URI”的人(包括我)实际上都反对“相对路径”。

并且在实践中,大多数服务器端MVC框架都可以轻松生成带有绝对路径(例如)的相对URI,/absolute/path/to/the/controller问题就变成了“服务器实现是否应scheme://hostname:port在绝对路径之前加a”。像OP的问题一样。我对此不太确定。

一方面,我仍然认为建议服务器返回完整的uri。但是,服务器永远不要hostname:port像这样在源代码中对事物进行硬编码(否则,我宁愿退回到具有绝对路径的相对uri)。解决方案是服务器端始终从HTTP请求的“主机”标头中获取该前缀。不知道这是否适用于所有情况。

另一方面,客户端将http://example.com:8042和绝对路径连接起来似乎并不麻烦。毕竟,客户端在向服务器发送请求时已经知道该方案和域名了吗?

总而言之,我建议您使用绝对URI,最好使用绝对路径回退到相对URI,而不要使用相对路径


2
这是一个好答案(+1),除了最后的结论外,我同意。但是,在我的回答中,我认为HTTP规范通过示例将“绝对”定义为引用绝对路径,而不是完全限定的URI。因此,我不同意您的(2)-它一个绝对URI,但是客户端必须为其推断网络协议和主机的绝对URI,因此它不是完全合格的URI。因此,我也不同意您对(1)的定义,该定义既是完整URI也是绝对URI。
劳伦斯·多尔

感谢您的评论。我只是从文件系统中借用了绝对路径和相对路径的概念。除了不同的用语,我认为您的意见与我的意见没有实质性的区别。您还推荐表格1和2,反对表格3,不是吗?
RayLuo 2014年

2
实际上,我支持(2);我认为(1)要求后端必须具有大量HTTP特定知识(即有关特定HTTP环境的详细信息,而不是一般而言的HTTP),并且(3)似乎需要太多客户端。但是,我的推理是基于原始的规范草案,而示例在以后的版本中进行了更改,从而使我的推理无效。
劳伦斯·多尔

就我个人而言,我(尚未)完全相信HATEOAS,因此返回URI的需求对于API来说意义非凡。我只是没有看到以类似于浏览网站的方式在客户端上驱动我的API。用例似乎在很大程度上由即席功能驱动。
劳伦斯·多尔

@LawrenceDol我一开始对HATEOAS感到困惑。现在,我认为这是一个选择问题。您的客户可以肯定地使用adhoc函数来使用您的api,但是,如果他们/您愿意,他们/您仍然可以开发一种模式来遵循它们,这样客户就不必对每个确切的网址进行硬编码。那就是HATEOAS。
RayLuo 2014年

13

这取决于谁在编写客户端代码。如果您正在编写客户端和服务器,则没有太大的区别。您将痛苦地在客户端或服务器上构建URL。

但是,如果您要构建服务器,并且希望其他人编写客户端代码,那么如果您提供完整的URI,他们会更爱您。解决相对URI可能会有些棘手。首先,您如何解决它们取决于返回的媒体类型。Html具有base标记,Xml在每个嵌套元素中都可以具有xml:base标签,Atom feed可以在feed中具有一个基础,而内容中可以具有一个不同的基础。如果您没有为客户提供有关基本URI的明确信息,那么他们必须从请求URI或从Content-Location标头中获取基本URI!并注意尾随的斜线。基本URI是通过忽略最后一个斜杠右侧的所有字符来确定的。这意味着在解析相对URI时,尾部的斜杠现在非常重要。

唯一需要提及的其他唯一问题是文档大小。如果您要返回大量项目,其中每个项目可能具有多个链接,则在不压缩实体的情况下,使用绝对URL可以为您的实体添加大量字节。这是一个性能问题,您需要根据具体情况决定是否重要。


11

唯一真正的区别似乎是,如果客户端使用绝对URI而不是必须从相对版本构造它们,则对于客户端来说更容易。当然,这种差异足以让我去做绝对版本。


7

随着应用程序的扩展,您可能希望进行负载平衡,故障转移等。如果返回绝对URI,则客户端应用程序将遵循不断发展的服务器配置。


假设您将“绝对”定义为绝对路径(例如/xxx/yyy...),而不是定义为完全限定的URI(例如http://api.example.com/xxx/yyy...)。
劳伦斯·多尔

6

使用RayLou的三分法我的组织选择了偏爱(2)。主要原因是为了避免XSS(跨站点脚本)攻击。问题是,如果攻击者可以将自己的URL根注入到来自服务器的响应中,则随后的用户请求(例如具有用户名和密码的身份验证请求)可以转发到攻击者自己的服务器*。

有些人提出了能够将请求重定向到其他服务器以进行负载平衡的问题,但是(虽然这不是我的专业知识),我敢打赌,有更好的方法来启用负载平衡,而不必将客户端显式重定向到其他服务器。主机。

*请让我知道这种推理方法是否存在缺陷。当然,目标不是阻止所有攻击,而是至少阻止一种攻击途径。


很高兴我以前的回答对您的组织有所帮助。是的,我个人也更喜欢(2),即无方案的绝对路径。但是我很好奇你的推理。您如何强制客户仅接受无方案网址?通用客户端(例如浏览器)根本不会拒绝无方案的url。因此,我认为您必须先编写自己的客户端代码来验证url,然后才能真正关注它们?尽管从技术上讲这是可行的(但不一定有用),但这种客户端验证通常不属于REST或HATEOAS讨论的一部分。
RayLuo

3
我知道这是一篇过时的文章,但我只想指出,“如果攻击者可以将自己的URL根注入到返回的响应中”,这是胡说八道。如果他们可以在响应中的正确位置“插入自己的URL”,我敢打赌他们可以,就像用您自己的主机名替换主机名一样容易。因此,出于安全性的考虑,我认为它不是有效的论据。
Magnus Eriksson,

5

您应该始终使用完整的URL。由于URL都必须唯一,因此它充当资源的唯一标识符。

我也认为您应该保持一致。由于Location HTTP标头期望基于HTTP规范的完整URL,因此在创建新资源时,完整URL将在Location标头中发送回客户端。您在Location标头中提供完整的URL,然后在响应正文中的链接中提供相对URI,这很奇怪。


1
好吧,Location标头的HTTP规范说的是绝对URI。绝对URI必须包含一个方案(例如http)。
Mark Bober 2014年

但是问题不是如何构造无上下文的不透明标识符,而是在问如何构造链接。后者可以正确地推断“与本文档位于同一网络位置”,而这正是规范的Location标头示例所提供的-绝对URI,其中不包含URI方案或服务器的网络位置。尽管链接和ID经常混杂在一起,但它们并不是同一件事-前者具有上下文,后者则没有。
劳伦斯·多尔2014年

您可以发送指向您所谈论的规范部分的链接吗?
Mark Bober 2014年

绝对URI指定方案;并非绝对的URI被认为是相对的。URI也根据其是不透明还是分层进行分类。不透明URI是绝对URI,其特定于方案的部分不以斜杠字符('/')开头。不透明的URI无需进一步解析。不透明URI的一些示例是:mailto:java-net@java.sun.com新闻:comp.lang.java urn:isbn:096139210x
Mark Bober

1
嘿,不用担心的人。关于这些东西的另一点是,我见过人们使用hrefs作为ID。这样,客户端无需从某些配置文件和ID重构URL,它仅知道URL并可以基于URL进行缓存。
Mark Bober 2014年

2

大型API结果中的重要考虑因素是重复包含完整URI会产生额外的网络开销。信不信由你,gzip不能完全解决此问题(不确定原因)。当结果中包含数百个链接时,整个URI占用了多少空间,我们感到震惊。


2

使用绝对URI的一个缺点是无法代理api。

把它拿回来...不是真的。您应该使用完整的URL,包括域。


3
为什么绝对URI无法使用代理的主机名?
Ed Summers

1
目前正在解决这个确切的问题。我们希望所有请求首先经过某种“负载平衡”层。直接到服务器的绝对URI将破坏此模型。
mag382 2013年

1
我正在使用Nginx代理具有绝对URL的网站。它完全可以用等效的代理URL替换后端URL。具体来说,它是将windyroad.artifactoryonline.com(具有完全限定的URL和完全限定的重定向)转发到repo.windyroad.com.au
Tom Howard

2

关于优点,我看到要传输的字节数有所减少,但代价是客户端需要为(绝对)路径进行额外的处理。如果您不顾一切地保存每个字节,即使尝试将内容编码为gzip,正确使用缓存头,使用etags和客户端上的条件请求之后,最终还是有必要这样做的,但我希望返回的结果会更高你的努力是其他的。

关于弊端,我发现无法控制将来如何在资源之间引导客户端流(负载平衡,A / B测试等),我认为这对于管理Web是一种不良做法API。对于客户端,您提供的URL基本上不再是不透明的(请参阅URI opacity上的Web体系结构的Tim Berners-Lee Axioms)。最后,您有责任让客户满意他们对您的API的创造性使用,即使仅仅是关于您的URL空间的结构。如果你曾经需要允许一个明确定义的URL修改,考虑使用URI模板中所使用的超文本应用程序语言

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.