上下文
考虑以下情况:需要创建资源,但操作需要很长时间才能完成。
实际上,这种情况并不少见:毕竟,REST 不是在某些 CRUD 场景中操作几个数据库行。REST是关于任意资源的操作,资源可能需要大量的计算才能存在。
因此,您基本上有两种选择:
您将强制 API 客户端等待资源实际创建
您可以立即返回一些状态响应,并将创建推迟到以后的某个时间点
例
让我们创建一些不平凡的东西(我使用HTTPie工具):
1± http POST https://api.service.io/stars name='Death Star' 2HTTP/1.1 201 Created 3Location: /stars/12345
在这里,我们试图创造一颗死星,正如你所看到的,它被创造出来并被送回去。Location
现在,正如你可能想象的那样,创造恒星本身并不是一件容易的事,更不用说当我们想要像死星这样装备的东西时了。这意味着我们将不得不等待一段时间才能看到这种反应。201 Created
因此,我们的目标是初始化星形创建,获取确认消息,并享受一些乐趣,直到资源最终准备就绪(如果我们必须不时轮询以检查状态更新,我们就可以了)。
为什么等待并不酷
嗯,因为!
更严重的是,强制API客户端等待本身并没有错。如果在服务器端,你依赖于一些异步循环,并且可以处理疯狂的连接数量,并且如果最终的等待时间是几秒钟(对于你的目的来说是可以接受的),那么你绝对可以停止阅读这篇文章,而不会发现酷孩子已经使用了几年的方法。n
n
异步处理(做错了)
你的第一反应可能是:"如果我立即回来,但把实际的创作推迟到以后的某个时间点,那会怎么样?HTTP 201 Created
好吧,你不能那样做。如果您这样做,您将违反HTTP / 1.1:语义和内容协议(更确切地说是RFC 7231的第6.3.2节):
RFC 7231 的 6.3.2 节
201(已创建)状态代码指示请求已得到满足,并已导致创建了一个或多个新资源。请求创建的主要资源由响应中的"位置"标头字段标识,如果未收到"位置"字段,则由有效的请求 URI 标识。
在实际创建资源时必须使用该值,而不是排队等待创建。HTTP 201 Created
异步处理(正确完成)
假设我们有一些队列,我们可以在其中放置长时间运行的作业(由某些工作进程定期执行)。
现在,我们可以返回。201 Created
202 Accepted
RFC 6 的 3.3.7231 节
202(已接受)状态代码指示请求已被接受进行处理,但处理尚未完成。
如您所见,这正是我们所追求的!
我们知道要返回什么状态代码,那么标头呢?简单。API 将返回已创建的排队任务的位置,而不是实际资源的位置:Location
1± http POST https://api.service.io/stars name='Death Star' 2HTTP/1.1 202 Accepted 3Location: /queue/12345
:火: 专业提示:允许返回有效负载和响应,您应该利用这个机会返回一些有意义的东西(例如任务完成的ETA,当前状态等)。202 Accepted
实施说明
在延迟处理方面,有几个与实现相关的问题经常被问到。让我们回顾一下它们。
问题 1.如何了解资源何时最终可用?
您需要查询排队的任务(这就是 API 返回标头的原因):Location
1± http GET https://api.service.io/queue/12345 2HTTP/1.1 200 Ok 3 4<response> 5 <status>PENDING</status> 6 <eta>2 mins.</eta> 7 <link rel="cancel" method="delete" href="/queue/12345" /> 8</response>
:火: 专业提示:遵循 HATEOAS 约束,我们可以添加指向允许取消/删除排队任务的状态的链接。
问题 2.创建资源时会发生什么情况,队列任务资源如何更改?
创建资源后,API 应针对排队任务的所有后续请求使用状态代码进行响应:303 See Other
1± http GET https://api.service.io/queue/12345 2HTTP/1.1 303 See Other 3Location: /stars/97865
问题 3.创建完成后,如何处理任务资源?
在创建资源时,其相应的任务可用,您可以向其查询状态。
创建最初所需的资源后,有两种替代方法可以处理临时任务资源:
API 客户端必须发出请求,以便服务器清除它。在此之前,服务器将使用状态进行响应。删除后,将返回以供后续请求使用。
DELETE
303 See Other
404 Not Found
GET /queue/12345
或者,垃圾回收可以是服务器的工作:一旦任务完成,服务器可以安全地删除它并使用后续请求进行响应。
410 Gone
GET /queue/12345
:火: 专业提示:服务器可以为所有新的排队任务分配一些到期日期,并且无论完成状态如何,这些任务都会过期。这样,服务器会限制任何给定任务可以运行的时间(最大值)。这种策略并不违背所宣布的目的,并且允许资源永远不会存在。202 Accepted
引用
Thijssen, J. REST 中的异步操作
Thijssen, J. REST Cookbook
以上转自:https://farazdagi.com/posts/2014-10-16-rest-long-running-jobs/
以下转自:http://www.ruanyifeng.com/blog/2018/12/async-api-design.html?utm_source=tuicool&utm_medium=referral
网站的前后端通信,往往会有异步请求,这时应该怎么设计 API?
我最近读到一篇文章,作者介绍了他的做法,设计得很精细,我觉得值得借鉴,可以当作异步 API 的标准设计。
一、同步 API
为了便于比较,先看看同步 API 的设计。下面是一个很简单的例子。
客户端发出一个请求,要求创建资源。
POST https://api.service.io/stars name='Death Star'
服务器回应 201。
HTTP/1.1 201 Created Location: /stars/12345
201 Created
告诉客户端,请求成功,资源已经创建。新的资源的网址请看Location
字段。
二、异步请求
如果服务器不能立即返回结果,就形成了异步操作。
客户端的请求还是一样的。
POST https://api.service.io/stars name='Death Star'
服务器回应 202。
HTTP/1.1 202 Accepted Location: /queue/12345
202 Accepted
告诉客户端,请求已经接受,但还没有处理,可以去Location
字段查询进展。
除了上面的头信息,服务器的回应如果有数据体,可以返回一些有效信息(比如任务完成的估计时间、当前状态等等)。
三、查询进展
过了一段时间,客户端就发出请求,查询异步处理的进展。
GET https://api.service.io/queue/12345
服务器回应 200。
HTTP/1.1 200 Ok <response> <status>PENDING</status> <eta>2 mins.</eta> <link rel="cancel" method="delete" href="/queue/12345" /> </response>
200 Ok
告诉客户端,请求成功,具体情况查看数据体。数据体里给出提示,异步操作已成功或还需要等待。
四、异步操作成功
有一种特殊情况,用户查询异步操作的进展的时候,可能会希望,如果异步操作已经完成,就直接跳转到新资源。
这时,服务器回应 303。
HTTP/1.1 303 See Other Location: /stars/97865
303 see other
告诉客户端,重定向到不同的资源。Location
字段就是跳转的目标,也就是新资源的网址。
五、删除查询链接
一旦异步操作完成,客户端可以要求服务器删除查询链接。
DELETE https://api.service.io/queue/12345
服务器回应 204。
HTTP/1.1 204 No Content
204 No Content
告诉客户端,删除成功。以后,客户端再访问这个查询链接,服务器回应404 Not Found
。
如果客户端不删除查询链接,服务器完成异步任务后,也可以自动删除。客户端再请求这个链接,服务器回应410 Gone
,表示该链接永久性不再可用。
(完)
版权属于:月萌API www.moonapi.com,转载请注明出处