在RESTful Web服务中进行分页时如何避免泄漏?

时间:2016-09-23 15:00:30

标签: rest asp.net-web-api restful-architecture

我们有一个RESTful Web服务,它返回一组票证。由于返回的集合可能太大而无法在单个gulp中处理,因此我们添加了 offset limit 查询参数。我们的想法是运行查询,然后跳过第一个偏移记录,然后返回下一个限制记录。

问题是这可能会泄漏门票。

例如,假设在客户首次查询时有八张需要工作的票证:

ID STATUS
00 needs work
01 needs work
02 needs work
03 needs work
04 needs work
05 needs work
06 needs work
07 needs work

如果客户端请求需要工作的故障单,偏移量为0且限制为4,我们将返回:

ID STATUS
00 needs work
01 needs work
02 needs work
03 needs work

如果是其他人,那么做一些工作,将一些门票更改为:

01 doesn't need work
02 doesn't need work

如果客户端请求需要工作的故障单,偏移量为4且限制为4,则查询结果为:

ID STATUS
00 needs work
03 needs work
04 needs work
05 needs work
06 needs work
07 needs work

在我们跳过前四个记录后,我们将返回:

06 needs work
07 needs work

票据04和05将被跳过。

如果我们在每个后续的分页请求中返回故障单表,如果更改了之前页面上的故障单,我们就会泄漏故障单,以免它们超出查询结果。

我的一部分想知道这是多么重要。

客户端将在某种时间表上请求需要工作票证。当票数超过限制时,它将在多个调用中翻阅其余票,在每次调用时递增 offset 。如果我们什么都不做,我们有时会泄漏需要工作票据,但是下次客户请求新的需要工作票时,它们会被接收。

也就是说,泄露的门票只会在这张门票上泄露,它们会出现在下一张门票上。

但是,如果我们不泄漏门票很重要,除了在第一次通话期间保存所有需要工作门票的标识符之外,我没有看到任何解决方法,然后通过标识符集合进行分页,而不是通过票证本身。

例如,当客户端请求需要工作票证且偏移量为零时,我们可以使用所有需要工作的票证的ID填充第二个表,然后返回第一个<第二个表中的em> limit 票证。下一个调用,我们对第二个表使用 offset limit ,以确定要返回的票证。

这个问题是我们需要处理同时运行的多个客户端。因此,我们需要第二个表上的主键,我们可以根据请求中的内容与特定客户端进行匹配。

我希望能够在不给客户端程序员带来额外负担的情况下进行管理。但我不知道如何。

通过检查请求及其标题,我有什么办法告诉它它来自同一个客户端,而不是之前的请求吗?我找不到了。

我们目前正在回复标题中返回分页信息:

Paging-offset: 0
Paging-limit: 4
Paging-returnedCount: 4
Paging-totalRecordCount: 54

我在想的是,当我们进行分页时,我们可能会返回 Paging-collection 值,这会为第二个表提供一个键值。然后,我们可以要求客户端在使用 offset != 0发出请求时提供集合值。

这看起来合情合理吗?你认为这会给客户程序员带来太大的负担吗?

其他人如何解决这个问题?或者他们只是忽略它?

1 个答案:

答案 0 :(得分:0)

  

通过检查请求及其标题,我有什么办法告诉它它来自同一个客户端,而不是之前的请求吗?我找不到一个。

你不应该 - 无国籍协议。特别是,如果您尝试执行REST,则希望请求具有所有必要信息,以便新服务器可以在原始服务器忙时应答请求。

但可能性包括为每个客户提供自己的资源。您可以通过多种方式将请求与唯一资源进行匹配。

  

这个问题是我们需要处理同时运行的多个客户端。

作为一项规则,如果您可以为多个客户提供对资源的共同理解,而不是尝试为每个客户定制您的表示,那么REST的工作要好得多。

考虑一下:Alice查询了一堆工作,Bob改变了一些东西,然后Charlie查询了一堆工作。如果Charlie得到Alice的查询缓存的堆的表示(即,在Bob改变之前),你能忍受吗? Cuz,这就是网络的设计方式......

(它没有 - 你可以让每个响应设置一堆无缓存标头。但是你应该考虑的是,因为它可能试图告诉你REST架构约束不是非常适合你的问题。)

  

其他人如何解决这个问题?或者他们只是忽略它?

嗯,这是一个使你的迭代器失效的并发修改,对吧?也许你只是调整一下,强迫客户重新开始......

您可以查看AtomSyndication以及某些服务use it

对于你的情况,我可能会考虑解决问题;而不是向服务器询问具有某些属性的N票证,我会考虑向服务器询问某些范围内具有该属性的所有票证。客户端可以继续浏览范围,直到它填满自己的桶。

描述问题的另一种方法是尝试翻阅可变集合。

如果删除分页约束 - 每个请求总是从第一个请求开始提取N个未工作的票证,这非常简单。

如果删除可变约束 - 通过不可变列表进行分页是直截了当的。使可变列表不可变可能很容易 - 而不是要求列表的最新版本,您要求在某个特定时间点的列表版本。使用事件采购时,这是一个非常快乐的问题。

  

我们讨论过的一件事是让一个查询返回一个票证ID列表,这些票证ID足够小,可以一直返回所有票证ID,然后有第二个查询返回给定查询的单个票证。

另一个好的答案;这基本上就是网页的工作方式 - (相对)小的html负载,带有指向java脚本,媒体等的超链接,扩展了表示。