我应该使用哪个HTTP动词来触发REST Web服务中的操作?


80

我正在实现RESTful Web服务,可用的操作之一将是reload。它将用于重新加载配置,缓存等。

我们从一个简单GET的URI 开始,如下所示:(${path}/cache/reload不传递任何参数,仅调用URI)。我知道不应使用GET请求修改数据。

在RESTful Web服务中用来调用动作/命令的正确动词是什么?

重新加载是REST Web服务的命令,该命令重新加载自己的缓存/配置/等。它不是将信息返回给客户端的方法。

我想做的可能不是REST,但这仍然需要通过这种方式来完成。reload方法只是一个真实的示例,在应用程序范围内有意义,并且大多数答案都针对该示例,但是实际上,我只需要知道哪个动词即可触发不执行CRUD的操作,但仍会更改数据/州。

我在以下主题的Stack Overflow上找到了这个详细的答案:https ://stackoverflow.com/questions/16877968/


1
“重新加载”是应用程序刷新将要显示的数据的感觉吗?重新加载与再次获取数据之间有什么区别吗?
肖恩·雷德蒙德

1
@SeanRedmond不,数据没有发送到客户端。实际上,客户端是在对REST Web服务说要执行和内部命令(重新加载)。诸如:“数据库中的许多配置已更改,因此REST Web服务现在将它们重新加载到您的内存中”。
Renato Dinhani 2014年


您是否考虑过在适当的请求上使用标头参数?这听起来非常像是缓存刷新...
古兰经

Answers:


25

我认为此操作没有合适的动词,因为此事务并不是真正的“ RESTful”。“ s”和“ t”代表“状态转移”,此处未转移任何内容。或者,换一种说法,按照最严格的定义,诸如PUT和POST之类的动词始终与名词一起使用,而“ reload”仅具有动词。

这次重装可能不是RESTful的,但仍然可能有用,您只需要选择一种方式来进行处理并忍受或解释这是不寻常的。GET可能是最简单的。但是,在评论中有相当多的怀疑态度,因此您应该考虑是否需要执行此重新加载操作,因为其他事情并未完全执行应做的事情。


我同意这不是RESTful的,但可能有用。我认为您应该建议使用PUT,因为这可能是幂等的,但不是nullimpotent。
亚伦·格林沃尔德

@Aaron,幂等和零幂的比较都很好,但是如何确定什么时候不幂呢?
Craig

@Craig如果多次运行具有相同的效果,则运行一次具有相同的效果。如果运行一次或多次对服务器具有与运行零次相同的效果,则它是无效的。en.wikipedia.org/wiki/Idempotence
亚伦·格林沃尔德

5
@AaronGreenwald“无能的” [not-im-poht-nt] [not-im-pawr-tnt] -形容词-1 .玩单词“不重要”的反义词,形容词“重要”。2. 幽默… ;-)
Craig

@Craig我完全错过了:)
亚伦·

75

如果您想成为RESTful,请不要考虑动词来执行操作,而应考虑客户端执行某项操作后资源所处的状态

因此,使用上面的示例之一,您有一个正在发送电子邮件的电子邮件队列。您希望客户端将电子邮件队列置于已暂停或已停止等状态。

因此,客户端会将该资源的新状态放入服务器。可以像这个JSON一样简单

PUT http://myserver.com/services/email_service HTTP/1.1
Content-Type: text/json

{"status":"paused"}

服务器找出如何从当前状态(例如“正在运行”)变为“已暂停”状态/状态。

如果客户端在资源上执行GET,则它应返回其当前处于的状态(例如“已暂停”)。

这样做的原因以及REST之所以如此强大的原因是,您无需做任何事情就可以使服务器达到该状态。

客户端只说“这是您现在应该处于的状态”,然后服务器确定如何实现该目标。这可能是数据库中的简单翻转。它可能需要数千个动作。客户不在乎,也不必知道。

因此,您可以完全重写/重新设计服务器如何执行此操作,而客户端无关紧要。客户端只需要知道资源的不同状态(及其表示),而无需了解任何内部结构。


2
就我而言,这是正确的答案。在服务器上刷新数据不是幂等操作,并且GET完全不适合使用动词。 PUT是最合适的动词,因为可以将操作视为将缓存的“重载状态”更新为“重载”。
Jez 2015年

@Jez在这里,我也更喜欢这个答案。坚持使用电子邮件的隐喻,乍一看,想通过将邮件置于“发送”状态而不是仅仅发送(动作)来发送邮件确实很奇怪。但是,如果您考虑一下,那实际上与将其放入“发件箱”是一样的。实际上,当您告诉邮件系统发送邮件时,邮件系统本身可能会在内部对其进行排队。因此,API可以让您将邮件置于“发送”状态,并且API不必对此进行自我解释。
Craig

因此,通过扩展,如果您不希望消息继续发送,则将其置于“已计划”状态,并带有应该发布的日期/时间。如果是不完整的,你把它(或者是隐含/默认情况下),在“草案”状态,等等
克雷格

...虽然我认为在这种情况下我更喜欢POST而不是PUT,因为PUT也应该是幂等的,但是POST不受此约束。
Craig

1
您可以这样做,但最终它试图将方形钉插入圆孔中。客户端没有理由需要触发服务器“重新加载”任何东西,那只是糟糕的架构设计。服务器可以在每次调用时或以固定的时间间隔更新其内部状态。依靠客户端告诉服务器重新加载某些独立于资源状态的实际请求的东西不是RESTful体系结构。
Cormac Mulhall 2015年

32

其他一些答案(包括已接受的答案)建议您使用GET(尽管不是很热情)。

我不同意。

首先,所有其他告诉您这不是理想的并且不是真正的RESTful是正确的。在适当的RESTful场景中,您需要处理服务器上的资源,并添加,更新,删除,检索等资源。当请求完成时,PUT应该发送代表有效资源的有效负载,而POST应该发送代表要添加到服务器的资源的有效负载。GET应该返回服务器上的资源。

您有一个不是RESTful的RPC(远程过程调用),您想在服务器上执行某些操作。因此,如果您尝试创建纯RESTful API,则应重新考虑您在做什么。

也就是说,有时您确实需要稍微修改规则。特别是如果您正在开发不会向公众公开的内部api,则可能会决定权衡是值得的。

如果这样做,我将建议使用PUT或POST,具体取决于RPC是否为幂等

通常,我们说HTTP PUT映射到SQL UPDATE,而HTTP POST映射到SQL INSERT,但这并不是完全正确的。一种更纯粹的陈述方式是HTTP PUT应该是幂等的,而HTTP POST则不必。这意味着您可以多次调用同一PUT请求,而不会产生副作用。一旦调用它,再次调用它是无害的。但是除非您打算这样做,否则您不应重复调用POST请求-每个POST都会再次更改服务器上的数据。

在您的情况下,如果您需要此重载功能,我建议您使用PUT,因为它听起来像幂等。但是我仍然敦促您考虑其他人对根本不需要它的看法。


6

POSTPUT用于提交实体到Web服务器的HTTP动词。使用PUT,提交的实体是给定URI上资源的(新)表示形式,不符合您的要求。POST适用于传统的表单处理程序,其中实体是资源的辅助数据,因此是赢家。该实体将包括命令或动作(例如“ action = reload”)。

也就是说,有问题的命令可能不应该通过REST接口公开。听起来好像出现了“重新加载”的必要性,因为可以通过其他一些通道(例如文件系统,DB客户端)来更改数据。缓存应该是透明的。而且,HTTP请求应该是原子的,甚至考虑通过其他渠道发送的消息。提供用于配置设置的“重新加载”命令似乎不必要。要求它是一种脆弱的设计。通过另一个通道进行更新后,将“重新加载”暴露给清理是肮脏的,因为一个通道不包含整个对话。相反,请考虑以下之一:

  • 完全通过REST进行更新
  • 将命令暴露给另一个通道
  • 自动化动作

其中一些选项可能不可行,具体取决于存在其他限制。

另请参见“ REST中的PUT与POST ”。


谢谢。我删除了编辑的“内部”,因为实际上“重新加载”方法旨在公开使用。我只是试图表示它指的是Web服务本身。我认为发布“行动”将是一个很好的方法。
Renato Dinhani 2014年

@RenatoDinhaniConceição:即使没有“内部”,它仍然会闻起来。您也许应该问一个新的问题,即设计是否是一个好的设计。
2014年

4

我会争论为什么客户请求将明确需要调用以刷新类似内容。听起来这应该是更典型的GET实现(即Pull数据,但服务在提取数据之前刷新数据)上的隐藏逻辑,或者是远离客户端的后端中的另一个触发器。

毕竟,数据/配置只需要在后续调用中保持最新状态,因此我将更倾向于懒惰而不是急于进行数据刷新。显然,我在这里承担了很多责任,但是我将退后一步来重新评估这种显式且独立的调用的必要性。


看我的编辑。“ reload”不是返回数据的命令。它指的是REST Web服务本身。一般而言,我的问题是关于在REST Web服务中触发操作的。其他示例可以是:email_queue/stop_sending_emails。我只想使用RESTful接口向某物发出命令。
Renato Dinhani 2014年

5
我仍然同意。在本地进程上调用SIGHUP很有意义,因为计算机应该信任可以访问该信号的本地登录人员。但是对于无状态,可访问Internet的协议呢?也许Web服务应该根据需要通过轮询或文件监视自动重新加载。此调用应该完全没有必要。

1
我同意。诸如配置和缓存之类的事情对于客户端来说是透明的。也许您应该给我们更具体的描述您的端点将被呼叫的情况。
本杰明·霍奇森

3

为什么不将动作视为资源。因此,由于要更新缓存,因此可以在系统中发布新操作。

对于纯粹主义者,您可以为此设置专用的网址。请注意,您可以扩展它,并在数据库(或任何存储)中记录日期,状态,用户等的实际操作。这只是我的想法。

系统范围内的通用操作/ actions / {action}

特定于资源类型/ actions / {resource} / {action}的操作

特定于资源/ actions / {resource} / {id} / {action}的操作

在您的情况下,缓存可能是系统范围的/ actions / reload_cache


0

我应该使用哪个HTTP动词来触发REST Web服务中的操作?

在考虑REST服务的细节时,考虑这种启发式通常很有用:如何在网站上实现它?

HTML只能本地描述GET和POST请求。这样我们就可以开始搜索了。

是否GET合适?要回答这个问题,我们需要考虑允许客户和中间组件进行的假设GET。的语义GET安全的

由于对目标资源应用安全方法,客户端不会请求也不希望原始服务器上的任何状态更改。同样,合理使用安全方法不会对原始服务器造成任何伤害,财产损失或异常负担。

因此,这意味着客户端和中间组件可以自行决定是否需要频繁调用GET请求,以满足他们自己的关注。蜘蛛程序可以随意获取资源以更新其索引。缓存可以预取。在不可靠的网络上,丢失的消息可能会按需要重试,以确保至少一个响应。

它将用于重新加载配置,缓存等。

如果这些都是昂贵的事情,那么您可能不希望客户自行决定发出这些请求。

POST另一方面,实际上不受限制-这大大减少了允许通用客户端进行的假设。您不会获得发出推测性POST请求的组件,因为这样做会出错-标准中没有任何内容可以说是可以的。

PUTPATCHDELETE...这些都是超过特定语义不安全的方法POST; 它们是否合适将取决于您的资源模型。

要记住的一个重要想法是HTTP方法属于文档域(请参阅Jim Webber的2011演讲),您描述的效果可能不属于文档域,而是在更改文档时调用的副作用。 。在如何组织文档以完成工作方面,这给了您很多自由。

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.