当前位置:  开发笔记 > 前端 > 正文

在休息集合中分页

如何解决《在休息集合中分页》经验,为你挑选了4个好方法。

我有兴趣将直接REST接口暴露给JSON文档集合(想想CouchDB或Persevere).我遇到的问题是GET如果集合很大,如何处理集合根上的操作.

作为一个例子假装我暴露StackOverflow的Questions表,其中每一行都作为文档公开(不一定是这样的表,只是一个相当大的'文档'集合的具体例子).收集将在可提供/db/questions与通常的CRUD API GET /db/questions/XXX,PUT /db/questions/XXX,POST /db/questions是在玩.获取整个集合的标准方法是,GET /db/questions但如果天真地将每一行转储为JSON对象,那么您将获得相当大的下载和服务器上的大量工作.

解决方案当然是分页.Dojo 通过一个巧妙的RFC2616兼容扩展使用带有自定义范围单元的标头,在其JsonRestStore中解决了这个问题.结果是只返回请求的范围.这种方法优于查询参数的优点是它为查询留下了查询字符串(例如,或某些,以及是的,它被编码).Rangeitems206 Partial ContentGET /db/questions/?score>200%3E

这种方法完全涵盖了我想要的行为.问题是RFC 2616指定206响应(强调我的):

请求必须具有包含Range头部字段(部分14.35),指示在期望的范围,并且可以具有包括一个If-Range头字段(部分14.27),以使所述请求为条件.

这在标题使用标题的上下文中是有意义的,但是是一个问题因为我希望206响应是默认处理天真客户端/随机人员探索.

我已经仔细研究了RFC,寻找解决方案,但对我的解决方案一直不满意,并对SO对这个问题的看法感兴趣.

我有过的想法:

返回200Content-Range头! - 我不认为这是错的,但我更喜欢一个更明显的指标,即响应只是部分内容.

返回400 Range Required - 所需标头没有特殊的400响应代码,因此必须手动使用和读取默认错误.这也使得通过Web浏览器(或像Resty这样的其他客户端)进行探索变得更加困难.

使用查询参数 - 标准方法,但我希望允许查询la Persevere,这会切入查询命名空间.

回来206吧! - 我认为大多数客户都不会惊慌失措,但我宁愿不反对RFC中的MUST

扩展规格!返回266 Partial Content - 行为与206完全相同,但是响应于不得包含Range标题的请求.我认为266足够高,我不应该遇到碰撞问题,这对我来说很有意义,但我不清楚这是否被视为禁忌.

我认为这是一个相当普遍的问题,我希望以某种事实上的方式看待这一点,所以我或其他人不会重新发明轮子.

当集合很大时,通过HTTP公开完整集合的最佳方法是什么?



1> Mohamed..:

我真的不同意你们中的一些人.我已经为我的REST服务工作了几个星期.我最终做的很简单.我的解决方案只对REST人们称之为集合的内容有意义.

客户端必须包含一个"范围"标题,以指示他所需的集合的哪个部分,或者当请求的集合太大而无法在单个往返中检索时,准备好处理413 REQUESTED ENTITY TOOALOOAL错误.

服务器发送206 PARTIAL CONTENT响应,Content-Range标头指定已发送资源的哪个部分,以及ETag标头以标识集合的当前版本.我通常使用类似Facebook的ETag {last_modification_timestamp} - {resource_id},我认为集合的ETag是它包含的最近修改过的资源的ETag.

要请求集合的特定部分,客户端必须使用"Range"标头,并使用从先前执行的请求获得的集合的ETag填充"If-Match"标头,以获取同一集合的其他部分.因此,服务器可以在发送所请求的部分之前验证集合是否未更改.如果存在更新版本,则返回412 PRECONDITION FAILED响应以邀请客户端从头开始检索集合.这是必要的,因为它可能意味着可能在当前请求的部分之前或之后添加或删除了某些资源.

我使用ETag/If-Match与Last-Modified/If-Unmodified-Since一起优化缓存.浏览器和代理可能依赖于它们中的一个或两个来进行缓存算法.

我认为URL应该是干净的,除非它包含搜索/过滤查询.如果你考虑一下,搜索只不过是一个集合的局部视图.而不是汽车/搜索?q =宝马类型的URL,我们应该看到更多的汽车?制造商=宝马.


413是"请求实体太大",而不是"请求实体太大".这意味着您的请求大小(例如上载文件时)大于服务器愿意处理的大小.因此,使用它似乎并不完全合适.
我非常不同意使用`413`.这是一个错误代码,意味着客户端正在*发送*服务器因大小而拒绝接受的内容.不是相反!请参阅https://tools.ietf.org/html/rfc7231#section-6.5.11(请注意,它表示**请求**有效负载.不是**响应**有效负载)!
固定它。我的意思是413。谢谢杰森。

2> Julian Resch..:

我的直觉是HTTP范围扩展不是为您的用例而设计的,因此您不应该尝试.部分响应意味着206,并且206只有在客户要求时才发送.

您可能想要考虑一种不同的方法,例如在Atom中使用的方法(设计中的表示可能是部分的,并且返回状态200,并且可能是分页链接).请参阅RFC 4287和RFC 5005.


Dojo的使用完全符合规范.如果服务器不理解`items`范围单元,它将返回完整响应.我熟悉Atom,但这不是Rest分页的一般解决方案.这不是单个案例的解决方案,而是一般解决方案的更多解决方案.并非所有文档/集合都适合Atom模型,除非有必要,否则没有理由强制它.

3> John Gietzen..:

您还可以返回Accept-Ranges,并Content-Ranges200响应代码.这两个响应标头为您提供了足够的信息来推断206响应代码明确提供的相同信息.

我会Range用于分页,并让它简单地返回200一个平原GET.

这感觉100%RESTful 并且不会使浏览变得更加困难.

编辑:我写了一篇关于此的博客文章:http://otac0n.com/blog/2012/11/21/range-header-i-choose-you.html



4> Vitorio..:

如果有多个回复页面,并且您不想立即提供整个集合,这是否意味着有多个选择?

在请求中/db/questions,返回300 Multiple Choices带有Link指定如何到达每个页面的标头以及带有URL列表的JSON对象或HTML页面.

Link: <>; rel="http://paged.collection.example/relation/paged"
Link: <>; rel="http://paged.collection.example/relation/paged"
...

Link每个结果页面都有一个标题(空字符串表示当前URL,每个页面的URL相同,只是使用不同的范围访问),并且根据即将发布的Link规范将关系定义为自定义的.这种关系可以解释您的自定义266或违反206.这些标题是您的机器可读版本,因为您的所有示例都需要了解客户端.

(如果您坚持使用"范围"路线,我相信您自己的2xx返回代码,正如您所描述的那样,将是最好的行为.您应该为您的应用程序执行此操作,这样["HTTP状态代码是可扩展的. "],你有充分的理由.)

300 Multiple Choices说你应该为身体提供一种让用户代理选择的方式.如果您的客户理解,则应使用Link标题.如果是用户手动浏览,可能是一个HTML页面,其中包含指向特殊"分页"根资源的链接,该资源可以根据URL处理该特定页面的呈现? /humanpage/1/db/questions还是像那样可怕的东西?


对Richard Levasseur的帖子的评论提醒我一个额外的选择:Accept标题(第14.1节).回到oEmbed规范出来的时候,我想知道为什么没有完全使用HTTP,并且使用它们编写了一个替代方案.

保留初始天真HTTP 300 Multiple ChoicesLink标题和HTML页面GET,但不要使用范围,让新的分页关系定义Accept标头的使用.您的后续HTTP请求可能如下所示:

GET /db/questions HTTP/1.1
Host: paged.collection.example
Accept: application/json;PagingSpec=1.0;page=1

Accept标题允许您定义该类型(你的页面数)可接受的内容类型(JSON的回报),再加上可扩展的参数.从我的oEmbed文章中重复我的笔记(这里不能链接到它,我会在我的个人资料中列出),你可以非常明确地提供一个规范/关系版本,以防你需要重新定义page参数意味着什么在将来.

推荐阅读
雯颜哥_135
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有