HATEOAS:绝对或相对的url?
在使用HATEOASdeviseREST风格的Web服务时,将链接显示为完整的URL(“ http:// server:port / application / customers / 1234 ”)与只显示path(“/ application /客户/ 1234" )?
当人们说“相对的”时,有一种微妙的概念模糊。
按照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
棘手的是,当scheme和权限被省略时,“path”部分本身可以是绝对path(以“/”开始)或“无根”相对path。 例子:
- 绝对uri或全uri:
"http://example.com:8042/over/there?name=ferret"
- 这是一个相对uri,绝对path :“/ over / there”
- 这是一个相对的URI,有相对path :“这里”或“./here”或“../here”等
所以,如果问题是“服务器是否应该产生相对path的安宁响应”,答案是“否”, 详细原因在这里 。 我想大多数人(包括我)反对“亲戚”,实际上是反对“相对path”。
实际上,大多数服务器端MVC框架可以很容易地生成相对于具有绝对path的URI,例如“/ absolute / path / to / the / controller”,问题就变成了“服务器实现是否应该在scheme:// hostname :在绝对path前面的端口“。 就像OP的问题一样。 我不太确定这个。
一方面,我仍然认为服务器返回一个完整的uribuild议。 但是,服务器不应该像这样在源代码中硬编码hostname:port这个东西 (否则我宁愿用绝对path回退到相对的uri)。 解决scheme是服务器端始终从HTTP请求的“主机”头中获取该前缀。 不知道这是否适用于所有情况。
另一方面,客户端连接"http://example.com:8042"
和绝对path似乎并不麻烦。 毕竟,客户端在向服务器发送请求时已经知道该scheme和域名了吗?
总而言之,我推荐使用绝对path,可能是以绝对path回溯到相对path,从不使用相对path 。
这取决于谁在写客户端代码。 如果你正在写客户端和服务器,那么它没有太大的区别。 您要么承受在客户端或服务器上构buildURL的痛苦。
但是,如果您正在构build服务器,并希望其他人编写客户端代码,那么如果您提供完整的URI,他们将会更加爱您。 parsing相对URI可能有点棘手。 首先,如何解决这些问题取决于返回的媒体types。 Html具有基本标记,Xml可以在每个嵌套元素中都有xml:base标记,Atom提要可以在提要中具有基础,而在内容中可以具有不同的基础。 如果您没有为您的客户端提供关于基本URI的明确信息,那么他们必须从请求URI或Content-Location头获取基本URI! 注意那尾随的斜线。 基本URI是通过忽略最后一个斜杠右侧的所有字符来确定的。 这意味着当parsing相对URI时,结尾斜杠非常重要。
唯一需要提及的另一个问题是文档大小。 如果您要返回大量项目,其中每个项目可能有多个链接,如果您不压缩该实体,则使用绝对URL可以为您的实体添加大量的字节。 这是一个性能问题,您需要根据具体情况决定是否具有重要意义。
唯一真正的区别似乎是,如果客户端使用绝对URI而不是从相对版本构build它们,那么对客户来说更容易。 当然,这种差异足以影响我做绝对的版本。
随着应用程序的扩展,您可能希望进行负载均衡,故障转移等。如果您返回绝对URI,那么您的客户端应用程序将遵循不断发展的服务器configuration。
使用RayLou的三分法,我的组织select了倾向于(2)。 主要原因是避免XSS(跨站点脚本)攻击。 问题是,如果攻击者可以将自己的URL根插入到从服务器返回的响应中,则可以将后续的用户请求(例如带有用户名和密码的authentication请求)转发给攻击者自己的服务器*。
有些人提出了能够将请求redirect到其他服务器进行负载均衡的问题,但是(我不是这方面的专长),我敢打赌,有更好的方法来启用负载均衡,而不必明确地将客户端redirect到不同的主机。
*请让我知道这个推理中是否有任何缺陷。 目标当然不是要阻止所有的攻击,而是至less有一个攻击的途径。
您应该始终使用完整的url。 它作为资源的唯一标识符,因为URL都是唯一的。
我也会争辩说,你应该是一致的。 由于Location HTTP标头需要基于HTTP规范的完整URL,因此在创build新资源时,完整的URL将在位置标头中发送回客户端。 在位置标题中提供一个完整的URL,然后在响应正文中的链接中提供相对的URI,这会很奇怪。
使用绝对URI的一个缺点是api不能被代理。
收回…不正确。 你应该去一个完整的url,包括域名。
大型API结果中的一个重要考虑因素是重复包含完整URI的额外networking开销。 信不信由你,gzip并没有完全解决这个问题(不知道为什么)。 当结果中包含数百个链接时,我们对整个URI占用了多less空间感到震惊。