http PUT可以修改标识符吗?

Can http PUT modify the identifier?

Restful API:

PUT /product/{id}

上面的 http 请求能否在其主体中指定不同的 id,以便实际更改原始记录的 id (假设 id 在底层存储中在技术上是可变的).

这似乎验证了 Restfulidempotent 规则 PUT
但我不确定,(即使通过 Google 搜索后)

有什么想法吗?

是的,上面的 http 请求 可以 在其正文中指定不同的 ID。

您可以将任何 JSON 文档放入此 PUT 请求的正文中。 well-behaved 实现会拒绝错误的文档,但错误的实现可以接受它,即使它违反了幂等规则。可以说(事实上,实际上)这不会是 RESTful。

首先,PUTspecified 作为:

The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response. However, there is no guarantee that such a state change will be observable, since the target resource might be acted upon by other user agents in parallel, or might be subject to dynamic processing by the origin server, before any subsequent GET is received.

根据该定义,通过 PUT“移动”资源将违反 HTTP 规范,因此 REST,因为无法通过相同的 URI 再次检索资源,以防万一URI 也应反映更新后的 ID,并且不实施重定向。但是,您可以自由使用 POST 代替,因为这里的有效负载是根据资源自己的语义处理的。请注意,实际负载(资源状态)的变化并不是实际问题,但根据规范,URI 的“替换”才是问题。

根据 Fielding 的说法,resource 是任何可以命名的东西,例如某个文档、某处发生的事件的图片。甚至其他资源的集合也可以是资源本身。 Fielding 将资源描述为时间到一组等效的实体或值的映射。这里的值可以是资源表示 and/or 资源标识符。这意味着资源因此可以随时间变化。这种行为每天都可以在网络上看到,即

在论文的 chapter 6.2 中,Fielding 谈到了 REST 如何应用于 URI。

... The definition of resource in REST is based on a simple premise: identifiers should change as infrequently as possible. Because the Web uses embedded identifiers rather than link servers, authors need an identifier that closely matches the semantics they intend by a hypermedia reference, allowing the reference to remain static even though the result of accessing that reference may change over time. REST accomplishes this by defining a resource to be the semantics of what the author intends to identify, rather than the value corresponding to those semantics at the time the reference is created. It is then left to the author to ensure that the identifier chosen for a reference does indeed identify the intended semantics. ...

... a resource can have many identifiers. In other words, there may exist two or more different URI that have equivalent semantics when used to access a server. It is also possible to have two URI that result in the same mechanism being used upon access to the server, and yet those URI identify two different resources because they don't mean the same thing.

Semantics are a by-product of the act of assigning resource identifiers and populating those resources with representations. At no time whatsoever do the server or client software need to know or understand the meaning of a URI. ...

虽然资源的内容可能会随着时间的推移而改变,因此资源可能会使用不同的内部记录 ID(或类似的),但值得怀疑的是,产品是否真的改变了(那么多)仅仅通过给它一个不同的ID?在这种情况下,最好不要在 URI 本身中使用内部产品 ID,而是使用任意值,例如一般的 UUID。由于客户端不应该解释或尝试从 URI 中提取含义,因此 URI 中的字符实际上在 REST 架构中并不那么重要。相反,应该使用有意义的 link-relations 来允许客户端确定 URI 的使用。

在 REST 架构中,客户端仅处理协商的(因此支持的)表示,因此仅处理服务器提供的信息。如果服务器需要来自客户端的输入,它将为客户端提供客户端知道如何操作的表单表示。在 Web 上,通常可以通过 link 等专用元素或搜索字段列出或搜索产品,其中可供性(基本上可以使用该元素做什么)很清楚。在这样的系统中,在其自己的结果页面上显示的产品列表可以使用 customized link-relation names 来提示客户有关具体产品的信息,并附加一个 link 客户仅在有兴趣与之交互时调用该特定产品。因此,客户端不必解析或解释 URI,而只需知道 link-relation 本身的含义或 use-case。同样的交互模型和可供性概念也应该用在 REST 架构中。

可以设置(临时)重定向到新产品“页面”,以允许仍具有旧版本产品 URI 的客户继续与该资源交互并获取有关新位置的更新。这将基本上允许任何 HTTP 操作像以前一样工作。特别是由于缓存,某些客户端可能还不知道位置更改,因为它们可能会通过其本地或中间缓存获得 still-fresh-enough 表示。因此,重定向将是一个合理的选择。

总结:

  • 使用 PUT 基本上“移动”资源并生成不同的目标 URI 因此违反了 HTTP 规范,因此违反了 REST。应改用 POST 的回退。
  • 避免将产品的内部 ID 包含到 URI 中,以将产品的标识符与实际 URI 分离,以便即使在内部标识符发生变化时也可以重用 URI。这可能需要在服务器端映射哪个产品在哪个 URI 上公开。这与 Mike Amundsen 相得益彰,他声称 你的数据模型不是你的对象模型不是你的资源模型不是你的可供性模型
  • 实施从旧 URI 到新 URI 的(临时)重定向,以允许旧客户端仍然与产品交互