如何在 REST API 中为“尚未准备好,稍后再试”选择 HTTP 状态代码? [关闭]

Posted

技术标签:

【中文标题】如何在 REST API 中为“尚未准备好,稍后再试”选择 HTTP 状态代码? [关闭]【英文标题】:How do I choose a HTTP status code in REST API for "Not Ready Yet, Try Again Later"? [closed] 【发布时间】:2012-04-05 09:15:57 【问题描述】:

我正在开发一个 RESTful API,其中http://server/thingyapi/thingyblob/1234 返回与thingy #1234 关联的文件(又名“blob”)以供下载。但可能是在服务器中不存在文件时发出请求,但绝对在以后可用。服务器中有一个批处理过程,可以为所有事物生成所有 blob。 Thingy 1234 已经存在,并且它的数据(而不是 blob)已经可用。服务器还没有生成 1234 的 blob。

我不想返回 404;那是为了不存在的东西。这是一个存在的东西,但它的 blob 尚未生成。有点像正在“处理”的 YouTube 视频。我认为重定向代码也不合适;没有“其他”网址可供尝试。

在这种情况下返回的正确 HTTP 状态代码是什么?

【问题讨论】:

Somewhat related 首先,如果 thingy 1234 还没有任何 GET-able 表示,它在什么意义上作为资源存在(从客户端的角度来看)?事实上,在服务器内部有一个队列作业来创建 1234,这似乎并不意味着资源 1234 存在。其次,客户端从哪里获得 URI .../thingyblob/1234?在资源实际上可以获取之前,服务器可能不应该向客户端提供该 URI。 HTTP 标准提供了有关在哪些情况下使用哪些状态代码的指南。因此,这个问题并非真正主要基于意见 204“无内容”怎么样? Is 表示服务器已经成功处理了请求并且[此时]没有返回任何内容。 这是如何基于意见的?有一套非常清晰的代码可以使用。 【参考方案1】:

另一个选项:503 - Service Unavailable

【讨论】:

According to W3C这不是你想对客户说的(虽然它在某种意义上意味着“再来一次”):“由于临时过载或维护,服务器当前无法处理请求服务器的. 这意味着这是一个临时条件, 将在一些延迟后缓解. 如果知道, 延迟的长度可以在 Retry-After 标头中指示. 如果没有给出 Retry-After, 客户端应该像处理 500 响应一样处理响应。” 服务不可用,服务可用但处理未完成。所以 503 可能不是一个好主意。【参考方案2】:

“问题”,例如,在服务器端:客户端发出了格式良好的请求,但服务器不能满足它。所以我倾向于“服务器错误”,5xx 状态码。

Quoth RFC 7231(当前的 HTTP 标准,已添加重点):

5xx(服务器错误)类状态码表示服务器 意识到它有错误或无法执行 请求的方法。除了响应 HEAD 请求时, 服务器应该发送一个包含解释的表示 错误情况,以及它是临时还是永久情况。

注意

“erred or is incapable to perform the request”:尽管它们的标题是“服务器错误”,但它们不仅仅用于服务器错误。 “临时或永久”:这些代码适用于暂时不可用的资源,例如您的资源。

在可用的代码中,我认为503, "Service Unavailable" 是最合适的:

503(服务不可用)状态码表示服务器 由于临时过载,目前无法处理请求 或定期维护,这可能会在一段时间后得到缓解 延迟。服务器可以发送一个 Retry-After 头域...来建议一个适当的时间量 客户端在重试请求之前等待。

注意:

“可能会在延迟一段时间后得到缓解”:您的情况是这样。 “临时过载”:对于您的情况而言,这不是迂腐的。但是,可以说,如果您的服务器速度更快,那么当客户端发出请求时批处理就已经完成了,所以它是一种“过载”:客户端要求资源比服务器提供的速度更快。 重试适合您的服务,因此您的回复应包含Retry-After 值。您可以提供批处理的下一次执行的估计完成时间或批处理的执行间隔作为值。

定义你自己的 5xx 状态码(例如 591),虽然 permitted 会有错误的语义:

客户必须 了解任何状态代码的类别,如第一个所示 digit,并将无法识别的状态代码视为等效于 该类的 x00 状态码

客户会将您自己的状态码视为500, "Internal Server Error",这是不对的。

【讨论】:

我看不出它比 202 好多少:benramsey.com/blog/2008/04/… @JCCyC 您的博客为响应创建内容的请求(POST 或 PUT)返回 202 提供了一个很好的案例。这个问题似乎是在询问 GET 返回什么。 @JCCyC 它可以被视为一种不同的未就绪状态:想象该资源的 ajax,您更喜欢 202 作为成功状态还是 503 作为错误状态?这样您就可以在应用对响应的反应的上下文中隐含地看到您更喜欢哪种含义 注意:“Retry-After”也可以与 307 - TEMPORARY REDIRECT 一起使用,如果您想在资源“准备就绪”时强制客户端在其他地方等待,这很好" 这不是服务器的问题。不应使用 5xx 代码。用例是系统的预期和有效状态。部分生成的记录与部分功能的服务器不同。客户端也没有问题。他们要求在某个时候存在的有效资源。不应使用 4xx 代码。服务器的响应应该是“好的,但我仍在处理它”(202 Accepted)。【参考方案3】:

由于您的资源尚未准备好,您可能知道(大约)它何时可用以及客户何时可以重试他的请求。这意味着您可能想要使用Retry-After header。此标头对 503(服务不可用)有效,这意味着整个站点因维护而停机,以及 3xx(重定向)响应。

在我看来,带有 Retry-After 标头的 302 (Found) 将是最佳选择,但我不确定响应标头的 Location 字段是否可以等于请求 url。反正是循环重定向。

【讨论】:

即使允许,如果客户端没有实现对 Retry-After 标头的支持,那么到同一页面的 3xx 重定向最终可能会以 503... (可选地使用 Retry -当然是在标题之后) Retry-After 也适用于 RFC 6585(2012 年 4 月)添加的 HTTP 429“请求过多”。如果资源还没有准备好的原因是客户端给服务器太多的工作要做,这可能是合适的。【参考方案4】:

我建议202 - Accepted。来自documentation:

请求已被接受处理,但处理尚未完成。 [...] 其目的是允许服务器接受对其他进程的请求(可能是一个每天只运行一次的面向批处理的进程)

【讨论】:

-1:这对于启动最终创建“thingy #1234”的过程的请求是有意义的,但对于随后为“thingy #1234”本身发出的 GET 请求则不适用。特别是,202 表明作为 GET 请求的结果,服务将在稍后的时间点发送“thingy #1234”的数据。这根本不正确。 它还说:“与此响应一起返回的实体应该包括请求当前状态的指示以及指向状态监视器的指针或用户可以期望何时完成请求的一些估计.",因此这将是让客户端知道 blob 尚未准备好的一种好方法,也是一种找出它何时准备好的方法。 我认为“接受处理”表示您正在保存请求以供稍后处理。如果只是被忽略,您应该返回一个 4xx 或 5xx 代码,以向客户表明他们可能想再试一次。 102(处理)有时似乎也是一个合理的选择,即使它在 webdav 规范中。 不能不同意这个答案。服务器没有返回任何东西,也没有计划返回(因为这个请求不做任何处理——无论如何它不应该为 GET 做任何处理)。因此,资源以某种方式对客户端不可用。这应该被视为错误,因此没有 2XX 代码是合适的。 4XX 或 5XX 空间中的东西。该请求 “已被接受处理”,该请求实际上已被丢弃【参考方案5】:

我不想返回 404;那是为了不存在的东西。

该 URL 与对事物的请求不对应。

http://server/thingyapi/thingyblob/1234

客户端正在请求一个不存在的thingyblob。如果它存在,你会把它给他们。

404.

【讨论】:

我很高兴有人这么说!我不敢相信有这么多人认为503 是适当的回应。更不用说其他一些奇怪的建议了。 虽然我同意 404 是这里最合适的响应,但它并没有回答 OP 的问题,即如何指示事物何时可用 :-)。我认为 Retry-After 字段似乎是最好的候选者,但它只能正式用于 503 和 3xx 代码。 @Jason:我认为这解释了一些奇怪的建议。 我认为这是最好的答案。您可以在 404 响应中返回正文。身体可能会表明该东西将在以后提供。或者也使用 Retry-After 标头。此处的标准需要稍微扩展一下,因为它不能很好地涵盖这种情况。 人们已经太习惯于 404 意味着页面未找到,当在 API 的上下文中他们无法从逻辑上分离它。 这真是太棒了 404。Thingyblob 还不存在,或者永远不存在。对于 http,它是否可用是无关紧要的。目前它不存在,它的 404。它什么时候可用是另一个问题,可以通过从服务器向客户端推送消息来解决,比如 thingyblob:1234 可用。再次执行获取,瞧..【参考方案6】:

501 - 未实施

就像它的声音一样。尚未实施但暗示未来可用性的功能。

这是summary of 5xx errors的链接。

【讨论】:

对于这个问题,听起来该功能本身存在,但所请求的项目不存在。 @Luke 501 在我的回答中的链接中的描述,'......它缺乏满足请求的能力。通常这意味着未来的可用性'。这完全满足了 OP 的要求。无论数据是否存在于他的服务器或数据库中。最终结果是目前无法通过 API 访问它。因此 API 无法满足请求,但希望通过 http 代码暗示它将来会可用。【参考方案7】:

409 冲突

表示由于请求中的冲突而无法处理请求,例如多次更新时的编辑冲突。 [来源***。]

这可能是合适的。

如果您无法通过返回数据来满足请求 - 那么它就不会成功。我认为 202 表明服务器已将请求排队,稍后将完成请求。但是在您的情况下,请求现在是针对数据的并且失败了。如果您稍后重试,这是一个不同的请求。

我认为您有冲突..您想要数据..但它正在编辑/更新。如果 Thingy1234 已经存在并且之前已成功下载,但现在正在编辑过程中在编辑过程中不可用,也会出现这种情况。

【讨论】:

不知道为什么这被否决了。对我来说似乎是正确的答案。来自 RFC:“409(冲突)状态代码表示由于与目标资源的当前状态冲突而无法完成请求。此代码用于用户可能能够解决的情况冲突并重新提交请求。" 您请求了一个服务器无法返回的资源,因为服务器正在更新该资源 - 即由于资源的当前状态。客户端可以通过等待并重新提交来解决这个问题 @Adam 我认为“用户可能能够解决冲突”的含义是,除了等待之外,重新提交会有所不同。【参考方案8】:

我认为423 - Locked可以用于此目的:

423 (Locked) 状态码表示方法的源或目标资源被锁定。此响应应包含适当的前置条件或后置条件代码,例如“lock-token-submitted”或“no-conflicting-lock”。

【讨论】:

优秀的答案!我想知道为什么它没有更多的赞成票。 可能是因为它是WebDAV HTTP代码? 从 akka-http 有 StatusCode RetryWith = reg(c(449)("Retry With", "The request should be retryed after doing the proper action.")) 那里的动作是等待然后重试 在很多方面我都同意这一点。我有类似的情况(在我的情况下,从可能尚未填充的索引中搜索)。从语义上讲,我认为这是正确的。但是,423 的 RFC 声明 “此响应应包含适当的前置条件或后置条件代码,例如 'lock-token-submitted' 或 'no-conflicting-lock'。” 不确定如何应用在这里。就我个人而言,我会选择 409 Conflict,但没有 cmets 就被否决了 - 不知道为什么?

以上是关于如何在 REST API 中为“尚未准备好,稍后再试”选择 HTTP 状态代码? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django Rest Framework 的 REST API 中为数组数据编写序列化程序?

如何在 Lumen/Laravel 中为 REST API 集成 Swagger?

如何在 Nginx 中为 Janus REST api 和 socket api 设置反向代理?

请求令牌时如何在 Azure 存储 Blob 中为 REST 请求指定范围? [AZURE-BLOB][REST API]

如何在 Laravel 中为 REST API 创建身份验证

如何使用rest api在一个信号中为用户设置标签