正确的 API 方法可延长处理时间

Ger*_*obs 4 http

我正在制作一个主要由数据库提供的 HTTP Web API。简单来说,数据库包含用户对象。
这些对象有一个last_online(当用户在线时)和last_checked(我上次检查用户对象时)。

检查用户对象可能需要 3 到 30 秒的时间。当last_checked时间少于10分钟时一切正常;API 调用返回200和用户对象。

但我想当数据超过 10 分钟时重新处理用户对象。显然我不能让我的 API 返回坐在那里等待。

对于(有时)需要从长时间运行的进程返回数据的 HTTP API,正确的方法是什么?

Eri*_*ein 5

我的第一个建议是让服务器作为后台进程每 X 分钟更新一次用户对象。我认为没有任何理由将保持服务器数据最新的负担交给客户端。对调用的响应GET将包含Expires标头。然后,客户端可以将响应缓存固定的时间,从而节省服务器点击次数,直到数据刷新。

如果您必须使刷新由客户端驱动,您希望GET返回一个202 Accepted,它指示 API 正在处理但尚未完成的有效请求。从您的请求返回的实体GET应提供一个时间戳,指示 API 何时应检查以获取更新的数据。刷新数据后,GET将返回200 Ok刷新后的数据。这是我推荐的方法。

GET /userObject
<- 202 Accepted
{ "checkAt": <timestamp> }

GET /userObject
<- 200 OK
{ "userName": "Bob", ... }
Run Code Online (Sandbox Code Playgroud)

您还可以考虑Retry-After在响应中使用标头,但这仅适用于503 Service Unavailable各种3xx (Redirection)响应中的任何一个。你绝对不是在描述一个503,而且听起来重定向也不正确。

如果您确实想走重定向路线,则需要返回一个302 Found,在标头中指定临时 URILocation并在标头中指定延迟时间Retry-After

第四种方法是使用 aPOSTPost-Redirect-Get模式。您可以POST使用您的 userObject URI 并让它返回302 Found带有Retry-After标头的内容。

我真的不认为第三个或第四个选项能给你带来第二个选项所没有的任何东西,而且我认为这是最清楚的。三意味着您的资源当前位于不同的位置,但实际上并非如此。四将本质上的GET请求(给我用户对象)转换为POST(刷新用户对象,但仅在需要时才这样做)。

如果您确实决定遵循 @JonSkeet 的建议,您可能需要一个单独的资源,例如/userObjects/userObjectRequests。客户总是POST/userObjectRequests。如果 userObject 在后端有效,则会POST返回302to /userObjects。如果无效,POST将返回一个带有 ID 和预计完成时间的实体。客户端可以调用GET/userObjectRequests/{id}并且他们要么获得302userObject (如果已准备好),要么200获得带有 id 和新的估计完成时间的 a 。