首页 文章

REST Web应用程序中的分页

提问于
浏览
316

这是this question的更通用的重构(消除了Rails的特定部分)

我不确定如何在RESTful Web应用程序中的资源上实现分页 . 假设我有一个名为 products 的资源,您认为以下哪种方法是最好的方法,以及为什么:

1.仅使用查询字符串

例如 . http://application/products?page=2&sort_by=date&sort_how=asc
这里的问题是我不能使用整页缓存,并且URL不是很干净且易于记忆 .

2.使用页面作为资源和查询字符串进行排序

例如 . http://application/products/page/2?sort_by=date&sort_how=asc
在这种情况下,看到的问题是 http://application/products/pages/1 不是唯一的资源,因为使用 sort_by=price 会产生完全不同的结果,我仍然无法使用页面缓存 .

3.使用页面作为资源和URL段进行排序

例如 . http://application/products/by-date/page/2
我个人认为使用这种方法没有问题,但有人警告我这不是一个好方法(他没有给出理由,所以如果你知道为什么不推荐,请告诉我)

任何建议,意见和批评都非常受欢迎 . 谢谢 .

12 回答

  • 6

    我认为版本3的问题更多是“观点”问题 - 您是否将页面视为资源或页面上的产品 .

    如果您将页面视为资源,那么这是一个非常好的解决方案,因为第2页的查询将始终产生第2页 .

    但是,如果您看到页面上的产品作为资源,则您遇到第2页上的产品可能会更改的问题(旧产品已删除或其他),在这种情况下,URI并不总是返回相同的资源 .

    例如 . 客户存储指向产品列表页面X的链接,下次打开链接时,相关产品可能不再位于第X页 .

  • 0

    我同意Fionn的意见,但我会更进一步说,对我来说,Page是 not 资源,它是请求的属性 . 这使我只选择了选项1查询字符串 . 感觉很对 . 我真的很喜欢Twitter API的结构 . 不太简单,不太复杂,记录良好 . 无论好坏,这都是我的设计,当我在做某种方式而不是另一种方式时 .

  • 8

    HTTP具有很好的Range标头,也适用于分页 . 你可以发送

    Range: pages=1
    

    只有第一页 . 这可能会迫使你重新思考什么是页面 . 也许客户想要一系列不同的商品 . Range标头也可用于声明订单:

    Range: products-by-date=2009_03_27-
    

    获得比该日期更新的所有产品或

    Range: products-by-date=0-2009_11_30
    

    获得比该日期更早的所有产品 . '0'可能不是最好的解决方案,但RFC似乎想要一些范围的开始 . 部署的HTTP解析器可能无法解析单位= -range_end .

    如果header不是(可接受的)选项,我认为第一个解决方案(查询字符串中的所有内容)是一种处理页面的方法 . 但请,请按字母顺序规范化查询字符串(sort(key = value)对) . 这解决了“?a = 1&b = x”和“?b = x&a = 1”的区分问题 .

  • 61

    选项1似乎是最好的,因为您的应用程序将分页视为生成相同资源的不同视图的技术 .

    话虽如此,URL方案相对无关紧要 . 如果您将应用程序设计为 hypertext-driven (因为所有REST应用程序必须按定义),那么您的客户端将不会自己构建任何URI . 相反,您的应用程序将提供指向客户端的链接,客户端将遵循它们 .

    您的客户可以提供的一种链接是分页链接 .

    所有这一切的令人愉快的副作用是,即使你改变了关于分页URI结构的思想并在下周实现完全不同的东西,你的客户也可以继续工作而不做任何修改 .

  • 3

    我一直使用选项1的样式 . 缓存并不是一个问题,因为在我的情况下数据经常变化 . 如果允许页面大小可配置,则无法再次缓存数据 .

    我没有发现网址难以记住或不清洁 . 对我来说,这是查询参数的很好用途 . 资源显然是一个产品列表,查询参数只是告诉你如何显示列表 - 排序和哪个页面 .

  • 102

    奇怪的是,没有人指出选项3具有特定顺序的参数 . http // application / products / Date / Descending / Name / Ascending / page / 2和http // application / products / Name / Ascending / Date / Descending / page / 2

    指向相同的资源,但具有完全不同的URL .

    对我来说,选项1似乎是最可接受的,因为它明确区分 "What I want""How I want" 它(它们之间甚至有问号大声笑) . 可以使用完整URL实现整页缓存(无论如何,所有选项都会遇到同样的问题) .

    使用Parameters-in-URL方法,唯一的好处是干净的URL . 虽然你必须想出一些方法来编码参数并无损地解码它们 . 当然你可以去URLencode / decode,但它会让网址丑陋:)

  • 11

    我更喜欢使用查询参数offset和limit .

    offset :用于集合中项目的索引 .

    limit :用于物品数量 .

    客户端可以简单地按如下方式更新偏移量

    offset = offset + limit
    

    为下一页 .

    该路径被视为资源标识符 . 页面不是资源,而是资源集合的子集 . 由于分页通常是GET请求,因此查询参数最适合分页而不是 Headers .

    我用metamug . 他们有这个可配置的 . Pagination on select query metamug

  • 24

    我目前在我的ASP.NET MVC应用程序中使用类似于此的方案:

    例如 http://application/products/by-date/page/2

    特别是: http://application/products/Date/Ascending/3

    但是,我不满意以这种方式在路由中包含分页和排序信息 .

    项目清单(本例中的产品)是可变的 . 即,下次有人返回包含分页和排序参数的URL时,他们得到的结果可能已经改变 . 因此, http://application/products/Date/Ascending/3 作为一个指向一组定义的,不变的产品的唯一网址的想法将丢失 .

  • 35

    寻找最佳实践我遇到了这个网站:

    http://www.restapitutorial.com

    在资源页面中有一个下载.pdf的链接,其中包含作者建议的完整REST最佳实践 . 除此之外还有一个关于分页的部分 .

    作者建议使用Range标头和使用查询字符串参数添加对两者的支持 .

    Request

    HTTP标头示例:

    Range: items=0-24
    

    查询字符串参数示例:

    GET http://api.example.com/resources?offset=0&limit=25
    

    其中offset是起始项目编号,limit是要返回的最大项目数 .

    Response

    响应应包含一个Content-Range标头,指示要返回的项目数以及尚未检索的项目总数

    HTTP标头示例:

    Content-Range: items 0-24/66
    
    Content-Range: items 40-65/*
    

    在.pdf中,针对更具体的案例还有一些其他建议 .

  • 1

    我倾向于同意slf“页面”不是真正的资源 . 另一方面,选项3更清晰,更易于阅读,并且可以更容易被用户猜到,甚至在必要时输入 . 我在选项1和3之间徘徊,但没有看到任何理由不使用选项3 .

    此外,虽然它们看起来不错,但有人提到使用隐藏参数的一个缺点,而不是查询字符串或URL段,用户无法书签或直接链接到特定页面 . 根据应用程序的不同,这可能是也可能不是问题,但需要注意的事项 .

  • 4

    我之前使用过解决方案3(我写了很多django应用程序) . 而且我认为它没有任何问题 . 它和其他两个一样具有可生成性(如果你需要做一些质量刮擦等),它看起来更干净 . 此外,您的用户可以猜测网址(如果它是一个面向公众的应用程序),并且人们喜欢能够直接前往他们想要的地方,并且网络猜测会让人感到有能力 .

  • 0

    我在我的项目中使用以下网址:

    http://application/products?page=2&sort=+field1-field2
    

    这意味着 - “给我页面第二页按字段1递增,然后按字段2递减” . 或者,如果我需要更多的灵活性,我使用:

    http://application/products?skip=20&limit=20&sort=+field1-field2
    

相关问题