这是对这个问题的更通用的重构(消除了Rails的特定部分)
我不确定如何在RESTful Web应用程序中的资源上实现分页.假设我有一个被调用的资源products
,您认为以下哪个是最好的方法,以及为什么:
例如.http://application/products?page=2&sort_by=date&sort_how=asc
这里的问题是我不能使用整页缓存,并且URL也不是很干净且易于记忆.
例如.http://application/products/page/2?sort_by=date&sort_how=asc
在这种情况下,看到的问题是它http://application/products/pages/1
不是一个独特的资源,因为使用sort_by=price
可以产生完全不同的结果,我仍然不能使用页面缓存.
例如.http://application/products/by-date/page/2
我个人认为使用这种方法没有问题,但是有人警告我这不是一个好的方法(他没有给出理由,所以如果你知道为什么不推荐,请告诉我)
任何建议,意见和批评都非常受欢迎.谢谢.
我同意Fionn,但我会更进一步说,对我而言,Page 不是资源,它是请求的属性.这使我只选择了选项1查询字符串.感觉很对.我真的很喜欢Twitter API的结构.不是太简单,也不是太复杂,记录良好.无论好坏,这都是我的"走向"设计,当我在做某种方式而不是另一种方式时.
我认为版本3的问题更多是"观点"问题 - 您是否将页面视为资源或页面上的产品.
如果您将页面视为资源,那么这是一个非常好的解决方案,因为第2页的查询将始终产生第2页.
但是,如果您看到页面上的产品作为资源,则您遇到第2页上的产品可能会更改的问题(旧产品已删除或其他),在这种情况下,URI并不总是返回相同的资源.
例如,客户存储指向产品列表页面X的链接,下次打开链接时,相关产品可能不再位于第X页.
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"的区分问题.
选项1似乎是最好的,只要您的应用程序将分页视为生成相同资源的不同视图的技术.
话虽如此,URL方案相对无关紧要.如果您将应用程序设计为超文本驱动(因为所有REST应用程序必须按照定义),那么您的客户端将不会自己构建任何URI.相反,您的应用程序将提供指向客户端的链接,客户端将遵循它们.
您的客户可以提供的一种链接是分页链接.
所有这一切的令人愉快的副作用是,即使您改变了关于分页URI结构的想法并在下周实现完全不同的东西,您的客户也可以继续工作而无需任何修改.
我总是使用选项1的样式.缓存并不是一个问题,因为在我的情况下数据经常变化.如果允许页面大小可配置,则无法再次缓存数据.
我没有发现网址难以记住或不清洁.对我来说,这是一个很好的查询参数使用.资源显然是一个产品列表,查询参数只是告诉你如何显示列表 - 排序和哪个页面.
奇怪的是,没有人指出选项3具有特定顺序的参数. http // application/products/Date/Descending/Name/Ascending/page/2 和 http // application/products/Name/Ascending/Date/Descending/page/2
指向相同的资源,但具有完全不同的URL.
对我来说,选项1似乎是最可接受的,因为它清楚地区分了"我想要什么"和"我多么想要"它(它们之间甚至有问号大声笑).可以使用完整URL实现整页缓存(无论如何,所有选项都会遇到同样的问题).
使用Parameters-in-URL方法,唯一的好处是干净的URL.虽然你必须想出一些方法来编码参数并无损地解码它们.当然你可以使用URLencode/decode,但它会让网址再次丑陋:)
我更喜欢使用查询参数offset和limit.
offset:表示集合中项目的索引.
限制:项目数.
客户端可以简单地按如下方式更新偏移量
offset = offset + limit
为下一页.
该路径被视为资源标识符.页面不是资源,而是资源集合的子集.由于分页通常是GET请求,因此查询参数最适合分页而不是标题.
我用metamug.他们有这个可配置的. 选择查询metamug上的分页