REST问题:PUT一个表述,GET另一个表述?

6

问题简述:

在特定URI上使用“GET”是否需要与在该URI上使用“PUT”的内容匹配?

我认为不需要。原因如下:

由于资源是一个理论上客户端无法了解的抽象事物,因此当我们进行PUT时,我们只能发送一种表示。根据RFC2616的梳理,对于具有许多(可能是无限的)表示形式的资源而言,似乎并没有完全规定它意味着什么,但以下是我的想法;请告诉我您是否同意:

我期望如果我向资源PUT一个表示形式,则该URI上所有其他资源的表示形式都应保持一致(必要时进行更新)。换句话说,您正在告诉资源“使用此表示形式来重新定义自己”。

因此,我应该能够执行以下操作:

PUT /resources/foo/myvacation
Content-type: image/jpg
...

然后进行以下操作:

GET /resources/foo/myvacation
Accept: image/png
...

并以不同格式获取已更新版本的myvacation(假设服务器知道如何执行此操作)。从中推断出来,这个组合的原子“图像+元数据” PUT也是合法的:

PUT /resources/foo/myvacation
Content-type: multipart/form-data

Content-disposition: form-data; name="document"
Content-type: image/jpg
[..]
Content-disposition: form-data; name="iptc"
Content-type: application/iptc
[..]
Content-disposition: form-data; name="exif"
Content-type: application/exif
[..]

然后,因为服务器端内容协商(RFC2616第12.1节)可以基于几乎任何东西进行,我们可以为此使用“document”内容的默认值:

GET /resources/foo/myvacation
Content-type: image/jpg
[..]

或者如果您像我一样相信RFC 2396第3.4节“查询组件是要由资源解释的信息字符串。”,则具有查询字符串的URI指向与不具有查询字符串的URI相同的资源,而且是与仅发送应用程序/x-form-urlencoded数据到资源等价的,则这也应该是合法的:

GET /resources/foo/myvacation?content=exif
Content-type: application/exif
[..]

PUT的说明如下:

PUT方法请求将封闭的实体存储在提供的请求URI下。

对我而言,这相当违反REST原则,除非你以非常自由的方式阅读它。我的解释是:“PUT方法请求基于所包含实体的表示,在提供的Request-URI处创建或更新资源。”
稍后我们得到以下内容:
“POST和PUT请求之间的根本区别反映在Request-URI的不同含义上。 POST请求中的URI标识将处理所包含实体的资源。该资源可能是接受数据的进程,其他协议的网关或接受注释的单独实体。相比之下,PUT请求中的URI标识了请求所附带的实体 - 用户代理知道预期的URI,服务器不得尝试将请求应用于其他资源。”
我们需要以类似的创造性方式阅读这个内容,但关键点在于“知道预期的URI”和“应用请求”。
因此,对我来说,在给定URI处通过GET返回的表示不一定与放置到给定URI的表示相同,它只需要是一致的。
正确还是错误?

我最近发现RFC2616已被RFC3986所取代,后者定义了查询(query)的用途,使其可以用于定位资源。我不确定我是否喜欢这个新定义。 :-/ - Jolly Roger
4个回答

5

基于内容协商可以从同一URI返回不同的表示形式这一事实,我很确定你放置(PUT)的内容不必与检索到的内容相同。


非常正确。使用Content-type头部,完全可以合法地POST一个XML对象,然后稍后再获取JSON或XHTML表示形式。这样的转换使得在许多不同的应用程序中使用您的Restful API更加简单。 - Lars Tackmann
@Darrel - 我同意,尽管未经协商的GET请求让我感到有点内疚。我依赖于“服务器端协商可以使用任何标准”的条款,这感觉比我想要的更加模糊。@Lars - POST是一个不同的东西。PUT的定义更加受限,因此我的问题。 - Jolly Roger

3
您的假设是正确的。GET请求不一定要返回与PUT相同的表示形式,但必须是相同的资源。
我目前正在开发一个Web应用程序,可以根据内容协商标头以XHTML、JSON或自定义XML方言的形式返回任何资源。因此,默认情况下浏览器将看到HTML。其他HTTP客户端,包括XMLHttpRequest,可以获取JSON等。它们都是同一URI上同一资源的表示形式。
同样,我们的应用程序将接受任何支持的格式(取决于问题中特定资源或集合的语义)的PUT或POST请求。

2
我同意其他答案的观点,即PUT的资源不需要与稍后GET的资源相同。我想在这个问题周围添加一些我的经验。
当依赖内容协商时,你需要非常小心。它很难正确处理,如果处理不当会导致用户遇到麻烦。让我们以图像为例...
如果Alice以原始格式放置图像,那么Bob可以通过服务器端的原始->jpeg转换以jpeg格式获取图像,而Alice可以以原始格式获取图像;没有问题。然而,如果Bob放置了一个jpeg,则没有办法将其转换回Alice的原始格式。对于度假照片来说,缺乏对称变换可能并不是什么大问题,但对于医学图像来说,就会有问题。
另一个缺乏对称变换的领域是在具有模式和另一个没有模式的表示中。在这种情况下,在服务器端,你最终会制定如何在它们之间进行转换的约定。但是,当你处理随时间而变化且不受你控制的模式文档时,你会遇到大问题。每次模式发生变化时,你都必须更新所有新模式形状的转换,并仍支持使用旧模式的资源。除了一些有限的情况外,内容协商很快变得更麻烦,而不值得。其中之一是如果你完全控制资源表示和其基础模式的区域。另一个领域是如果资源格式是标准的,并且可以在不同格式之间进行对称变换。

1
如果你在进行转换,那么你PUT的东西不应该和你GET到的东西一样,所以我不明白为什么会有问题。
但是,如果你PUT一个带有特定信息的用户,那么当你使用GET时,应该能够检索到该用户,就像当我上传了我的第四张度假照片后,当我调用GET时,我期望得到那张照片,但它可能会被转换成不同的格式,或者经过其他一些变换,但是,如果我得到的是第五张照片,那就是个问题。

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