REST、HTTP DELETE 和参数
Posted
技术标签:
【中文标题】REST、HTTP DELETE 和参数【英文标题】:REST, HTTP DELETE and parameters 【发布时间】:2011-02-02 02:55:17 【问题描述】:为 HTTP DELETE 请求提供参数有什么非 RESTful 的吗?
我的场景是我正在建模“你确定要删除它吗?”设想。在某些情况下,资源的状态表明请求的删除可能无效。您可以自己想象一些需要确认删除的场景
我们采用的解决方案是给删除请求传递一个参数,表示可以继续删除("?force_delete=true")
例如
DELETE http://server/resource/id?force_delete=true
我相信它仍然很平静,因为:
(a) DELETE 的语义没有改变 - 用户仍然可以发送正常的 DELETE 请求,但是这可能会失败并显示 409,响应正文将解释原因。我说可能会失败,因为(出于不值得解释的原因)在某些情况下没有理由提示用户。
(b) Roy 的论文中没有任何内容表明它违背了 REST 的精神——为什么会有,因为 HTTP 只是 REST 的一种实现,那么为什么传递 HTTP 参数很重要
有人可以指出一个明确的声明来说明这不是 RESTful 的原因吗?
在一个相关问题上,如果用户没有指定 force_delete,那么我将返回 409 Conflict
- 这是最合适的响应代码吗?
跟进
经过进一步研究,我认为在DELETE中添加参数可能会违反几个原则。
首先是实现可能违反了“统一接口”(参见Roy's dissertation的第5.1.5节
通过添加“force_delete”,我们在已经明确定义的 DELETE 方法上添加了一个额外的约束。这个约束只对我们有意义。
您也可以争辩说它违反了“5.1.2 客户端-服务器”,因为确认对话实际上是一个 UI 问题,而且并非所有客户端都希望确认删除。
有人建议吗?
【问题讨论】:
Roy 论文的网址包含一个“)”,导致 404。ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm 有效。 【参考方案1】:我认为这是不平静的。我认为 restful 服务不应该处理强制用户确认删除的要求。我会在 UI 中处理这个问题。
如果这是程序的 API,那么指定 force_delete=true 是否有意义?如果有人正在编写脚本来删除该资源,您是否要强制他们指定 force_delete=true 以实际删除该资源?
【讨论】:
您回复的第一段是您的意见,我尊重这一点,但您没有指出文献中禁止使用这样的 URI - 它仍然标识资源和最正在使用适当的 HTTP 动词。回答您的问题;是的,它仍然有意义(在我看来)。我希望脚本(可能基于 CURL)尊重 409 响应并向用户建议如何重新发送请求 - 所有这些都基于我的响应正文 关于将 Web API 与程序 API 进行比较的要点。这通常是确定 API 是否为 RESTful 的好方法。【参考方案2】:不,它不是 RESTful。您应该将动词 (force_delete
) 放入 URI 的唯一原因是,如果您需要在 PUT/DELETE 方法不可用的环境中重载 GET/POST 方法。从你使用DELETE方法来看,不是这样的。
HTTP 错误代码409/Conflict
应该用于存在冲突导致 RESTful 服务无法执行操作的情况,但用户仍有可能自行解决冲突。删除前确认(没有会阻止删除的真正冲突)本身并不是冲突,因为没有任何东西可以阻止 API 执行请求的操作。
正如 Alex 所说(我不知道谁对他投了反对票,他是正确的),这应该在 UI 中处理,因为这样的 RESTful 服务只是处理请求,因此应该是无状态的(即它不能依赖通过保存有关请求的任何服务器端信息来确认)。
如何在 UI 中执行此操作的两个示例是:
pre-html5:* 向用户显示一个 JS 确认对话框,并且只有在用户确认后才发送请求 HTML5:* 使用带有 DELETE 操作的表单,其中该表单将仅包含“确认”和“取消”按钮(“确认”将是提交按钮)(*) 请注意,5 之前的 HTML 版本本身不支持 PUT 和 DELETE HTTP 方法,但是大多数现代浏览器可以通过 AJAX 调用来执行这两种方法。有关跨浏览器支持的详细信息,请参阅this thread。
更新 (基于额外的调查和讨论):
服务需要 force_delete=true
标志存在的场景违反了 Roy Fielding 论文中定义的 uniform interface。此外,根据HTTP RFC,DELETE 方法可能会在源服务器(客户端)上被覆盖,这意味着这不是在目标服务器(服务)上完成的。
因此,一旦服务接收到 DELETE 请求,它应该在不需要任何额外确认的情况下对其进行处理(无论服务是否实际执行操作)。
【讨论】:
您能解释一下违反了哪个 REST 约束吗?考虑到 URI 对客户端应该是不透明的,为什么您认为使用删除一个资源但无法删除另一个资源的 HTTP DELETE 无法满足客户端的期望。我不确定 409 是返回的最佳状态代码,但除了有点奇怪的实现之外,我找不到任何被破坏的 REST 约束。 @Darrel:(恕我直言)它违反了统一接口,因为 DELETE 方法没有按照 HTTP 标准执行。考虑一个假定标准 REST 服务的 REST 客户端 - 服务如何让客户端知道它需要添加force_delete=true
?根据 HTTP RFC,DELETE 方法可能会在源服务器(客户端)上被覆盖,这意味着这不是在目标服务器(服务)上完成的。所以我的理解是,一旦服务收到 DELETE 请求,它应该在不需要任何确认的情况下处理它(不管服务是否实际执行操作)。
@Chris,你的第二点:是的,这也是我的理解,即状态表明存在真正的冲突而不需要确认。我刚刚注意到您在问题中所做的更新,我同意 - 当我自己研究它时,我得出了相同的结论(这违反了统一界面,并且应该在客户端/UI上进行确认边)。我还在这里遇到了一个非常有趣的线程,它可能会有所帮助:mail-archive.com/pylons-discuss@googlegroups.com/msg13578.html
@MicE 在很大程度上我同意你的看法,这不是处理这种情况的理想方式。我只是对“它不是 RESTful”标签有点挑剔。有一段时间,这句话被扔在了所有地方。但是,可以为媒体类型定义规则,如果您尝试删除资源并收到错误(我会说 403 禁止会比 409 更好),那么客户端应该尝试删除相关资源通过添加“force_delete=true”。在某种程度上,它有点像授权。执行 GET,获取 401,添加 auth 标头并再次 GET。
@Darrel:这是一个很好的观点,谢谢。而且我看到人们自己扔了 not RESTful 标签。可能是现在服务和 Web 应用程序之间的障碍变得非常模糊,所以一组人可以从纯服务的角度看到这一点,而另一些人则从混合的应用程序/服务的角度来看。这就是我相信关于如何进行确认的真正问题所在。 @Chris:更新了——谢谢先生,非常有趣的话题和讨论!【参考方案3】:
除了亚历克斯的回答:
请注意,http://server/resource/id?force_delete=true
标识的资源与 http://server/resource/id
不同。比如删除/customers/?status=old
还是/customers/
,差别很大。
【讨论】:
我不同意,我可以随意提供多个 URI 来标识同一资源。 是的 - 每个人都可以随意搞砸:-) 规范 URI 的指示可以帮助解决这个问题:googlewebmastercentral.blogspot.com/2009/02/… @Chris 应该只有一个 URI 可以返回资源的表示。其他 URI 可以引用相同的概念,但执行 GET 应该返回 303 See Other。为了反驳对此的明显反对意见,/foo.xml 和 /foo.json 是两个不同的资源。 @Darrell - 同意,但格式在这里不是问题。此外,.format 是 Rails 和其他框架中的约定,而不是 REST 的一部分 - 您应该使用 HTTP 中的内容协商与 MIME 或微格式来完全实现这一点。【参考方案4】:这是一个老问题,但这里有一些 cmets...
-
在 SQL 中,DELETE 命令接受一个参数“CASCADE”,它允许您指定也应删除相关对象。这是一个有意义的 DELETE 参数示例,但 'man rm' 可以提供其他参数。如果没有参数,这些情况如何在 REST/HTTP 中实现?
@Jan,URL 的路径部分标识资源似乎是一个公认的约定,而查询字符串则没有(至少不一定)。例子比比皆是:获取相同的资源但格式不同,获取资源的特定字段等。如果我们将查询字符串视为资源标识符的一部分,则不可能有“同一资源的不同视图”的概念无需求助于 HTTP 内容协商等非 RESTful 机制(出于多种原因,这可能是不可取的)。
【讨论】:
感谢您将其添加到对话中,即使它持续了数年以来并没有太多的对话。以上是关于REST、HTTP DELETE 和参数的主要内容,如果未能解决你的问题,请参考以下文章