【问题标题】:Use http status 202 for asynchronous operations使用 http 状态 202 进行异步操作
【发布时间】:2011-07-02 01:13:00
【问题描述】:

我正在为接受用户贡献数据的服务编写 REST API。我想保持所有操作完全异步,这包括 PUT、POST、DELETE 甚至 GET 请求。我的想法是接收请求,对其进行足够的处理以确保它是一个有效的请求,然后传递一个 HTTP 202 接受的响应以及一个数据最终可用的 url 和一个令牌,以便后续请求可以与处理后的数据相匹配.如果请求无效,我将发送 HTTP 400。

然后,客户端将负责检查我在将来某个时间提供给他们的 url 并传递令牌。如果数据可用,我会返回正常的 200 或 201,但如果我仍在处理请求,我将发送另一个 202,表示处理尚未完成。如果处理数据出现错误,我将根据需要发送 4xx 或 5xx 状态。

我想这样做的原因是我可以将所有有效请求转储到请求池中,并让工作人员从队列中拉出并处理可用的请求。由于我不知道池的大小或可用工作人员的数量,我无法确定我是否可以足够快地满足请求,以满足 Google App Engine 的 30 秒限制。

我的问题是:我是否通过以这种方式处理请求来破坏 REST?例如,浏览器似乎需要立即响应请求。对于我的 HTML 页面,我计划使用结构化页面进行响应,然后使用 AJAX 处理数据请求。

我对以这种方式使用 REST 处理数据的任何意见或经验最感兴趣。

【问题讨论】:

  • 您希望浏览器直接使用它吗?因为这个解决方案对于 API 来说似乎很好(参见 @systempuntoout 的回答),但它显然不适用于网络浏览器。
  • 我将尝试将浏览器限制为 GET 操作,其中最有可能的查询保存在内存中(例如 memcached)。任何长期查询都可能通过 AJAX 使用显示进度表的轮询来完成(例如过滤大型结果集)。 PUT 和 POST 可能类似于上传 youtube 视频,在服务器完成任务之前,我会给用户一个标准的“您的媒体正在处理中”消息。

标签: rest


【解决方案1】:

我认为您的解决方案很好,Http status 202 是在这种特定情况下使用的proper response,表示请求已被接受处理,但处理尚未完成 .

我会在您的工作流程中稍微改变的是后续请求的Http status

正如您所说,202 response 应该返回一个 Location header,指定客户端应该用来监控其先前请求状态的 URL。
调用这个 Check-the-status-of-my-process URL,而不是在进程挂起的情况下返回 202,我会返回:

  1. 200 OK 当请求的进程仍处于挂起状态时。响应应描述进程的待处理状态。
  2. 201 Created 处理完成时。 GET/PUT/POST 的响应应该包含请求/创建/更新资源的位置。

【讨论】:

  • 我同意您的状态回复。在我仍在处理时发送 200 OK 感觉有点尴尬,因为它表明“请求已成功”。然而 202 也表明请求已被接受,当我只是检查进度时情况并非如此。没有确切的状态来描述我想要什么,所以 200 可以代表“到目前为止还不错”。
  • 我同意这一点,但我认为201202 对后续请求没有意义。状态码用于指示请求/响应的状态——不是资源。在后续请求中坚持使用200,并使用表示来表示资源的状态。
  • 我同意@AviFlax。作为 202 的一部分,您返回了一个新 URL,它是代表请求的资源。因此,当用户执行 GET 以了解请求的状态时,200 是告诉他们请求状态的正确响应,无论它是否成功。 201 在这种情况下是没有意义的。请求完成后,您的正文应说明这一点,并给出最终请求的位置(或指向原始 URL,如果请求是 GET)。
  • Location 标头字段不应用于向客户端提供状态监视器,应使用响应正文,参见。 Roy Fielding’s clarification.
【解决方案2】:

把我的两分钱加到一个老问题上。我的想法类似于 systempuntoout 和 Avi Flax 的建议。

我同意 HTTP 202 响应适用于通过 Location 标头重定向到另一个资源的初始请求。

我认为Location URL 可能应该包含您引用的令牌,以符合Location 重定向的共同期望。例如Location: /queue?token={unique_token}Location: /task/{unique_token}

我还认为,当“检查状态”操作成功时,用于检查进程状态的资源应该返回 HTTP 200 响应(而不是 HTTP 202,因为这意味着当前请求已被“接受” )。

但是,我认为在创建新实体时,“检查​​状态”应该返回一个 HTTP 303 (See Other) 响应,并在新实体创建后返回一个 Location 标头。这比发送HTTP 201 更合适,因为刚刚执行了GET 请求以检查状态,因此没有创建任何内容。

我还认为用于检查状态的资源应该适当地返回错误代码。每当“检查状态”成功执行时,应返回适当的成功代码。可以在应用程序级别处理错误(通过检查响应正文)。

【讨论】:

  • 我喜欢使用 303 重定向让客户端在不同的 URL 完成请求的想法。查看您链接的维基百科页面也描述了它的用途,这正是我最初的目的。感谢您的回复。
  • Location 标头字段不应用于向客户端提供状态监视器,应使用响应正文,参见。 Roy Fielding’s clarification.
【解决方案3】:

这是一个非常古老的问题,但我想提出一个稍微不同的观点,我并不认为这是正确的,只是我的观点。

从客户的角度来看

让我们从最初的 HTTP 请求开始。首先,请求应该是 POST。您正在向服务器发送消息以创建资源。在这种情况下 GET 和 PUT 无效,因为:

  • GET 在此上下文中无效,因为 GET 旨在获取特定位置的资源
  • PUT 无效,因为您没有创建请求,而是要求服务器创建请求。

从服务的角度来看

所以现在您正在向服务器发送 POST 以处理请求。服务器实际上有 3 个可能的返回值(不包括 4xx 和 5xx 错误):

  • “201 Created”表示服务收到请求并能够立即或在可接受的时间段内处理它。这个时间段完全取决于服务设计。这由服务开发人员来定义。
  • “202 Accepted”表示服务收到请求并正在处理它。当服务知道某些事情需要一段时间时使用。另一种观点是,如果服务依赖于任何其他无法确定结果的异步操作,那么它应该返回“202 Accepted”响应。最后,一些服务设计者可能总是简单地返回“202 Accepted”,不管它可以多快完成。
  • 在某些情况下,您会收到“302 Found”。这通常是当服务可以将请求识别为生成已存在的资源(并且仍然有效且不处于错误状态)并且可以接受重用现有资源时。并非所有服务都这样工作:向线程发布评论应该始终创建新资源。其他服务会:发布一组标准以获取医生列表,生成相同的医生列表。如果这些信息可以重复使用,那就重复使用它。
  • 通过所有这些响应,“位置”HTTP 标头将返回给客户端,其中包含可以找到资源的位置。这很重要,有些人倾向于在方法上出现分歧,正如您稍后将看到的那样。如果资源可以与其他请求一起重用,那么“位置”实际上应该以相同的请求总是生成相同的 URL 的方式生成。这提供了大量的缓存和重用。

服务成功完成请求后,会在返回给客户端的位置创建资源。

现在我开始看到与上面的回复有些不同的地方。

如果服务未能完成请求,它仍应在返回给客户端的位置创建资源。该资源应指出失败的原因。让资源提供故障信息比尝试将其硬塞到 HTTP 协议中要灵活得多。

如果服务在完成之前收到对该资源的请求,它应该返回“404 Not Found”。我认为它应该是“404 Not Found”的原因是因为它确实不存在。 HTTP 规范并没有说“404 Not Found”只能用于当资源永远不会存在时,只是说它现在不存在。在我看来,这种对异步轮询流程的响应是完全正确的。

还有一种情况是资源应该只存在固定时间。例如,它可能是基于每晚刷新的源的数据。在这些情况下应该发生的是应该删除资源,但应该向服务提供一个指示符,它可以知道返回“410 Gone”状态代码。这基本上是告诉客户端资源在这里,但不再可用(即:可能已过期)。客户端的典型操作是重新提交请求。

再次站在客户的角度

当客户端收到其初始 POST 的响应时,它会获取“位置”并使用该 URL 使用 GET(同样,不是 POST)向服务发出请求。该服务通常会使用以下值进行响应:

  • “200 OK”表示请求已完成。请求的结果在内容正文中返回,以 Accept HTTP 标头定义的格式提供内容。
  • “404 Not Found”会告诉客户端请求还没有完成,资源还没有,在这种情况下,基本上应该稍后再试。
  • 如果客户端可能在很长一段时间后尝试获取资源但它不再存在,则会返回“410 Gone”。在这种情况下,它应该简单地重新提交原始查询

需要指出的一点是,返回的资源一般是可以定义成功和失败响应的格式。客户端应该能够从该资源中确定是否存在错误、错误是什么,并能够做出相应的响应。

另外,服务开发者可以让服务在短时间内过期并删除错误资源。

这就是我对这个问题的看法。聚会已经很晚了,但希望未来的读者可能会对一个常见问题有稍微不同的看法。

【讨论】:

  • 404 的问题在于它是可缓存的。 (见tools.ietf.org/html/…)。重试 404 直到它成功可能不是一个好的模式,而且看起来非常不标准。 4xx 错误是专门的客户端错误。 4xx 错误意味着客户端出错或未能传递访问资源所需的某些必需信息。在正常使用中,获取解析为 404 的 Location 标头是一个错误。 (例如,竞争条件或数据库一致性问题。)
  • 好点。 Cacheable 问题可以通过缓存控制 HTTP 标头来解决。关于第二点,这是一个很好的观点。从技术上讲,这并不是对 404 的错误使用,但您确实提出了一个合理的问题。
  • 您可以考虑使用 Content-Location 标头来检索操作的状态。否则我同意迪诺。可以在 Microsoft Azure 上找到 Content-Location 的灵感:docs.microsoft.com/en-us/rest/api/hdinsight/…
  • 我不同意这个答案,因为正如 AviFlax 所说,状态代码旨在指示 request 的状态,而不是 resource 的状态应在表示中注明,cf. RFC 7231,§ 6:“状态码元素是一个三位整数代码,给出了尝试理解和满足请求的结果。”
  • 此外,Location 标头字段不应用于向客户端提供状态监视器,应使用响应正文,参见。 Roy Fielding’s clarification.
【解决方案4】:

FWIW,Microsoft Flow 使用这样的模式。
第一次调用返回 202 w/ Location 标头。 后续电话返回: 1. 如果仍在处理 --> 202 带位置标头。 loc 标头可以不同,它提供了一种在调用之间传递状态的方法(并可能使服务器无状态!)。 2. 如果完成 --> 200。

详情在:https://github.com/jeffhollan/LogicAppsAsyncResponseSample

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-27
  • 2020-12-20
  • 2016-12-20
  • 2016-02-09
  • 2018-01-20
  • 1970-01-01
相关资源
最近更新 更多