题 HATEOAS:绝对或相对URL?


在使用HATEOAS设计RESTful Web服务时,将链接显示为完整URL的优缺​​点是什么(“HTTP://服务器:端口/应用/用户/ 1234“)与路径(”/ application / customers / 1234“)相比?


71
2018-02-10 18:39


起源




答案:


当人们说“相对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,绝对路径: “/在那边”
  3. 这是一个 相对uri,相对路径:“here”或“./here”或“../here”等

所以,如果问题是“服务器是否应该产生 相对路径 在宁静的回应“,答案是”不“和 细节原因可在这里找到。 我想大多数人(包括我)反对“相对uri”实际上反对“相对路径”。

而在实践中,大多数服务器端MVC框架都可以轻松生成 相对uri与绝对路径 例如“/ absolute / path / to / the / controller”,问题变成“服务器实现是否应该在scheme:// hostname:port前面填充绝对路径”。就像OP的问题一样。我对这个不太确定。

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

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

总而言之,我会说, 建议使用绝对uri,可能使用绝对路径回退到相对uri,从不使用相对路径


63
2017-08-29 08:02



这是一个很好的答案(+1)我同意,除了最后的结论。但是在我的回答中,我认为HTTP规范定义了, 通过例子,“绝对”是指绝对的 路径,而不是完全限定的URI。所以我不同意你的(2) - 它 是 绝对URI,但客户端必须推断出网络协议和主机,因此它不是完全限定的URI。因此,我也不同意你对(1)的定义 都 完整的URI和绝对URI。 - Lawrence Dol
感谢您的评论。我只是从文件系统借用绝对路径和相对路径概念。除了不同的术语,我认为你和我的意见没有实质性的区别。你还推荐表格1和2,你反对表格3,不是吗? - RayLuo
实际上,我是为了(2);我认为(1)要求后端必须具备许多HTTP特定知识(意味着关于特定HTTP环境的细节,而不是一般的HTTP),并且(3)似乎需要太多的客户端。 但,我的推理基于原始草案规范,并且示例在更高版本中以一种使我的推理无效的方式进行了更改。 - Lawrence Dol
就个人而言,我(但)根本不相信HATEOAS,因此返回URI的要求对于API来说非常有意义。我只是没有看到我的API以类似于浏览网站的方式在客户端上驱动;用例似乎非常由adhoc函数驱动。 - Lawrence Dol
@LawrenceDol我在开始时对HATEOAS有同样的困惑。现在我认为这是一个选择问题。您的客户可以使用adhoc功能来确保使用您的API,但如果他们/您想要,他们/您仍然可以为他们开发一个模式,以便客户端不需要对每个确切的URL进行硬编码。那就是HATEOAS。 - RayLuo


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

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

唯一需要提及的另一个问题是文档大小。如果要返回每个项目可能包含多个链接的大型项目列表,则在不压缩实体时,使用绝对URL可以向实体添加大量字节。这是一个性能问题,您需要根据具体情况决定它是否重要。


12
2018-02-10 21:11





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


10
2018-02-10 18:47





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


7
2017-11-23 04:14



只要将“绝对”定义为绝对路径(例如 /xxx/yyy...并且不是完全限定的URI(例如, http://api.example.com/xxx/yyy...)。 - Lawrence Dol


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

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


3
2017-10-03 21:43



嗯,Location标头的HTTP规范说绝对URI。绝对URI必须包含一个方案(例如http)。 - Mark Bober
但问题不在于如何构建无上下文的不透明 身份标识,它询问如何构建 链接。后者可能正确地推断出“在与此文档相同的网络位置”,这正是规范的一个例子。 Location header give - 绝对URI,不包含URI方案或服务器的网络位置。虽然链接和ID经常被混淆,但它们不是一回事 - 前者具有上下文,后者则不然。 - Lawrence Dol
你能发送一个你正在谈论的规范部分的链接吗? - Mark Bober
绝对URI指定方案;一个非绝对的URI被认为是相对的。 URI也根据它们是不透明还是分层来分类。不透明URI是绝对URI,其特定于方案的部分不以斜杠字符('/')开头。不透明的URI不需要进一步解析。不透明URI的一些示例是:mailto:java-net@java.sun.com news:comp.lang.java urn:isbn:096139210x - Mark Bober
嘿,不用担心男人。关于这个问题的另一点是我见过人们使用hrefs作为ID。因此客户端不需要从某个配置文件和id重建URL,它只知道URL并可以基于它进行缓存。 - Mark Bober


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

有些人提出了能够将请求重定向到其他服务器以实现负载平衡的问题,但是(虽然这不是我的专业领域)我会打赌有更好的方法来启用负载平衡,而不必明确地将客户端重定向到不同的主机。

*如果这种推理方式有任何缺陷,请告诉我。当然,目标不是防止所有攻击,而是防止至少一种攻击途径。


3
2018-05-20 01:35



很高兴我之前的回答对您的组织有所帮助。是的,我个人也更喜欢(2),a.k.a. scheme-less绝对路径。但是我很好奇你的推理。您是如何强制您的客户仅接受您的无计划网址的?通用客户端(例如浏览器)根本不会拒绝无方案的URL。所以我假设您必须编写自己的客户端代码以在实际跟踪它们之前验证URL?虽然这在技术上是可行的(但不一定有用),但这种客户端验证通常不是REST或HATEOAS讨论的一部分。 - RayLuo


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

把它拿回来......不是真的。你应该去一个完整的URL,包括域名。


2
2017-11-26 00:14



为什么绝对URI不能使用代理的主机名? - Ed Summers
目前正在解决这个问题。我们希望所有请求首先通过一种“负载平衡”层。直接服务器的绝对URI将破坏此模型。 - mag382
我正在使用Nginx代理具有绝对URL的站点。它完全有能力用等效的代理URL替换后端URL。特别是它的代理 windyroad.artifactoryonline.com (具有完全限定的URL和完全限定的重定向) repo.windyroad.com.au - Tom Howard


大型API结果中的一个重要考虑因素是重复包含完整URI的额外网络开销。信不信由你,gzip并没有完全解决这个问题(不知道为什么)。当结果中包含数百个链接时,我们对完整URI占用多少空间感到震惊。


1
2018-01-23 22:24