REST-通过Accept标头与扩展进行内容协商之间的权衡


40

我正在设计一个RESTful API。我们知道我们想为任何给定资源返回JSON和XML。我一直在想我们会做这样的事情:

GET /api/something?param1=value1
Accept:  application/xml (or application/json)

但是,有人为此使用扩展名,就像这样:

GET /api/something.xml?parm1=value1 (or /api/something.json?param1=value1)

这些方法的权衡是什么?未指定扩展名时最好依靠accept标头,但在指定扩展名时依靠荣誉标头吗?这种方法有缺点吗?


您正在使用什么网络服务器?以及它如何解析URL?
Dipan Mehta'3

1
我对事情的技术(服务器)方面一无所知。话虽如此,我更喜欢您的方法,因为它使用http标准,这使它更易于理解(例如,当有人应该在几年后对其进行一些维护时)。当未指定accept或具有意外值时,您可以依赖扩展名,但是我总是总是首先使用标准方法。
Treb 2012年

@Dipan我正在使用MVC4 Web API(仍处于beta版)对此进行破解。它使用ASP.NET的路由抽象,这非常好。
布兰登·林顿2012年

1
@Treb是的,我更喜欢使用accept标头值。我想知道同时支持两者是否有任何缺点。
布兰登·林顿

Answers:


38

这是“但是,从哲学上讲,第一种方法是唯一的方法。”,这是“正确的官方RESTful方法是使用Accept:标头”。人们普遍认为是这样,但也绝对不正确

这是Roy Fielding(定义了REST)的简短摘要...

“ 6.2.1节并未说应该一直使用内容协商。” 引用

那个特定的对话是在'Accept-Language:'头的上下文中进行的,但是同样的情况也适用于'Accept:'头,正如稍后在他的回复中所明确指出的...

“我不知道为什么人们看不到首页上的第二个和第三个链接

http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

指向两个PDF版本。”

他的意思是,将不同的端点用于同一源数据的不同表示形式没有任何问题。(在这种情况下,一个.html端点和两个不同的.pdf端点。)

同样在类似的讨论中,这次是关于针对不同媒体类型使用查询参数与使用文件扩展名的优点...

“这就是为什么我总是喜欢扩展的原因。这两种选择都与REST无关。” 引用

同样,这与“接受”和“文件名”扩展名稍有不同,但是菲尔丁的立场仍然很明确。

答案-确实没有多大关系。两者之间的权衡不是很明显,两者都是可以接受的样式。


3
伟大的平衡答案。我想有时我会补充说,从URI中“显而易见”是指某个特定内容。例如URI中的.html扩展名或.pdf扩展名。在这种情况下,实际上不需要支持内容协商,并且在URI中隐含内容可以使人们更轻松地共享URI并使用它以可以立即使用的方式链接到事物。在其他情况下(例如,您希望避免在URI中扩展)和/或要公开同样支持多种内容类型json / XML的Web API,accept标头可能更合适。
Tim Lovell-Smith

更新了答案以包含新链接。我认为雅虎组织改变了他们的结构。
菲尔·斯特金

我不同意。服务器返回的资源描述语言应该与服务端点执行的业务逻辑无关。只是为了容纳不同的资源描述语言而为同一服务端点具有多个URI,似乎对应该如何构造REST URI产生了误解。
Dejay Clayton'5

10

正确的官方RESTful方法是使用Accept:标头。

但是,您必须注意不要破坏可缓存性,这是REST的要求之一。您需要具有Vary: Accept可理解的标头和缓存。在理想的世界中,您会拥有它,但在现实生活中,您的年龄可能会有所不同。因此,第二种解决方案不是那么干净,但是可能更实用。

另外,请注意,一些非常老的浏览器过去常常忽略标题,而是依靠扩展名。


1
实际上不准确。查看已接受的答案。
菲尔·斯特金

9

从技术上讲,这并不重要-您的Web服务器将能够按照外观适当地对其进行处理。(我以为是这样,但看起来不像是一个热门产品)。

但是,从哲学上讲,第一种方法是唯一的方法。在REST中,URL实际上仅指向URI-仅仅是资源。想了一会儿这个资源相同的对象在面向对象的编程。您仅通过4种方法(也称为GET / POST / PUT / DELETE-或任何允许传输的方法)与该资源交谈,但是该方法不会成为对象的描述。同样,返回值也不是URI。该对象仍然是某物,而不是某物.xml某物.json

假设如果您不想使用Accept标头,但是如果您仍然想在哲学上真正地成为REST,那么我不会介意类似:

GET /api/something?parm1=value1&return_type=xml

相对于

GET /api/something.xml?parm1=value1 (or /api/something.json?param1=value1)

但是正如我所说,这种差异只是哲学上的。


+1 Dipan,除了一件事情之外,您是对的:/ api / something?return_type = xml 仍然不平稳。它不是RESTful的原因是URL不透明。从协议的角度来看,IOW在/ api / something / xml和/ api / something?xml之间没有区别。参见w3.org/DesignIssues/Axioms.html
Mark E. Haase

0

@vartec:我认为你错了

正确的官方RESTful原则说,HTTP头中不应隐藏任何内容,因为它是公开或引用的URI,有关请求/响应的任何详细信息都应作为URI的一部分提供

因此,我强烈建议避免使用标头获取有关请求和响应的详细信息,并坚持使用

 GET /api/something.xml?parm1=value1 (or /api/something.json?param1=value1)

我无法快速找到这些参考,但是我会回发它们(实际上,您可以参考O'reilly出版的书“ RESTful Web services”(http://shop.oreilly.com/product/9780596529260.do)确认相同


17
-1完全错误。一方面,该URL HTTP标头中发送。此外,每个不同的URL应该代表一个不同的资源。相同内容的XML和JSON编码显然不是2种不同的资源;它们是同一资源的2种不同表示形式。
Mark E. Haase 2012年

HTTP标头是存储“消息元数据”的合法且推荐的位置,例如:安全凭证,关联标识符,会话ID,事务上下文,数据格式。这种信息不应使您的URL或消息有效内容混乱。
Paulo Merson
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.