【问题标题】:Why odata Trippinservice returns only 8 pages?为什么odata Trippinservice只返回8页?
【发布时间】:2022-08-24 09:54:48
【问题描述】:

当我在浏览器中给出odata服务url时,https://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/People,我只得到8条记录。为什么总共只有8条记录People 实体中的 20 条记录?是否在 Trippinservice 中设置了 PageSize?谁能帮我理解这一点?

    标签: pagination odata paging odata-v4


    【解决方案1】:

    是的,这个服务实现了服务器端的分页。

    首先,我们通过响应中 @odata.nextLink 属性的存在来确定服务器端分页是有效的,它位于响应的根目录中:

    {
        "@odata.context": "http://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/$metadata#People",
        "@odata.nextLink": "https://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/People?%24skiptoken=8",
        "value": [
            ... 8 records ... 
        ]
    }
    

    我们只能认为通过计算响应中的记录数或查阅给定服务的文档,页面大小为8。在这种情况下,内部有一个$skiptoken 查询参数下一个链接,在这种情况下,它恰好有一个值8,这对应于记录的数量,但这只是巧合。
    笔记:%24 是一个美元符号 $ 已被 url 编码

    ~/TripPinServiceRW/People?%24skiptoken=8
    

    对于OData Basic Tutorial 中记录的TripPin 服务,$skiptoken 值表示要记录的记录数跳过并且是一个常见的实施,但它不是标准.

    文档中没有具体提及 People 提要的服务器页面大小,也没有标准方法来记录 $skiptoken 逻辑。$metadata.继续阅读如何为什么ASP.NET WebAPI 实现skiptoken:Use $skiptoken for server-driven paging

    我们可以通过导航下一个来证明这一点下一个链接或更改$orderby

    获取:~/TripPinServiceRW/People?$skiptoken=8

    {
        "@odata.context": "http://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/$metadata#People",
        "@odata.nextLink": "https://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/People?%24skiptoken=16",
        "value": [
            ... 8 more records ...
        ]
    }
    

    $skiptoken 现在是 16 在新下一个链接~/TripPinServiceRW/People?%24skiptoken=16。在许多实现中,$skiptoken 将代表钥匙发送的最后一条记录的值,但是TripPin不使用这个约定,我们可以通过改变顺序来验证:

    这两个响应都将在$skiptoken=8下一个链接

    获取:~/TripPinServiceRW/People?$orderby=UserName

    {
        "@odata.context": "http://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/$metadata#People",
        "@odata.nextLink": "https://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/People?%24orderby=UserName&%24skiptoken=8",
        "value": [
            ... 8 records ...
        ]
    }
    

    获取:~/TripPinServiceRW/People?$orderby=UserName desc

    {
        "@odata.context": "http://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/$metadata#People",
        "@odata.nextLink": "https://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/People?%24orderby=UserName+desc&%24skiptoken=8",
        "value": [
            ... 8 records ...
        ]
    }
    

    根据规范,$skiptoken 是一个任意令牌,服务可以使用它来检索下一个来自先前准备好的数据集的页面。 $skiptoken 的值对服务器本身具有特殊意义,它可以是任意令牌或指向某个页面的引用缓存的结果集。

    11.2.5.7 Server-Driven Paging
    仅包含由请求 URL 标识的部分项目集的响应必须包含一个链接,该链接允许检索下一个部分项目集。此链接称为下一个链接;它的表示是特定于格式的。最后的部分项目集不得包含下一个链接。

    OData 客户端必须将下一个链接的 URL 视为不透明,并且不得将系统查询选项附加到下一个链接的 URL。服务可能不允许更改使用下一个链接的后续页面请求的格式。因此,客户端应该使用兼容的Accept 标头在后续页面请求中请求相同的格式。 OData 服务可以在构建下一个链接时使用保留的系统查询选项$skiptoken。它的内容是不透明的、特定于服务的,并且必须只遵循 URL 查询部分的规则。

    值得在规范中强调这个非常具体的注释:

    OData 客户端在构造请求时不得使用系统查询选项 $skiptoken。

    $skiptoken 是一个服务器端实现,在许多情况下,您甚至无法猜测正确的值可能是什么。 TripPin 服务是一个非常简单的演示 API,它使用 8 的页面大小来说明服务器端分页的行为,考虑到整个数据集的小尺寸 (20),这是一个不错的任意数字,将导致多个页面最后一页只有部分已满。这足以测试服务器端支持数据接口的基本合规性。

    服务器端分页旨在鼓励搜索驱动用户优先制定更精确的搜索标准的界面浏览逐页浏览页面。Virtual Scrolling 是一种利用服务器端分页的常见用户界面范例。不同的语言和运行时有不同的实现,但基本上用户可以滚动数据列表或网格,当他们到达底部时,可能会有一个“加载更多”记录的链接(在幕后,这将加载来自下一个链接)。有时此链接不会显示,当用户接近或到达列表末尾时会自动加载数据。

    您仍然可以使用传统的客户端使用$top$skip 查询参数进行分页,但是一些服务实现服务器端分页仍会将结果限制为该服务器内部逻辑定义的固定行数。如果您正在实施客户端分页,那么您可能仍需要使用下一个链接检索每个结果的所有结果客户端结果页面。

    让我们通过首先获取第 2 页来比较客户端页面大小为 5:

    获取:~/TripPinServiceRW/People?$skip=5&$top=5

    {
        "@odata.context": "http://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/$metadata#People",
        "value": [
            ... 5 records ...
        ]
    }
    

    请注意,响应中没有@odata.nextLink 属性,这是因为请求的项目数没有超过服务器页面大小逻辑。所以让我们尝试页面大小为 9。这一次,要检索页面的所有记录,我们需要进行多次查询。

    这里的一般指导是递归地为每个下一个链接响应中的 url,如果它们包含下一个链接

    获取:~/TripPinServiceRW/People?$skip=9&$top=9

    {
        "@odata.context": "http://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/$metadata#People",
        "@odata.nextLink": "https://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/People?%24skip=9&%24top=9&%24skiptoken=8",
        "value": [
            ... 8 records ...
        ]
    }
    

    获取:~/TripPinServiceRW/People?%24skip=9&%24top=9&%24skiptoken=8

    {
        "@odata.context": "http://services.odata.org/V4/(S(ysqt4lcalbsipb1qkoc04ryb))/TripPinServiceRW/$metadata#People",
        "value": [
            ... 1 record ...
        ]
    }
    

    当您实现自己的符合 OData-v4 的 API 时,了解这一点很重要怪癖并在您的 API 文档中具体记录您的政策或惯例是什么服务器端分页以及启用它的集合。

    在我自己的实现中,我经常会禁用如果请求包含服务器端分页客户寻呼令牌$top$top 的值是 <= 200)但是

    从一个客户端如果你看到一个执行下一个链接响应中的属性并且您没有收到预期的记录数,那么您应该查询后续服务器页面如果您无法实施虚拟卷轴启用用户体验。


    笔记:通常,当我们讨论 OData v4 服务中的分页时,示例将包括使用 $count 查询选项。

    [11.2.9 请求集合中的项目数]:成功时,响应正文必须包含在应用任何$filter$search 系统查询选项后与请求匹配的项目的确切计数...

    返回的计数不得受$top$skip$orderby$expand 的影响。

    TripPin 服务不符合规范中的这个特定(和许多其他)子句,所以我没有在这个解释中使用那个查询选项。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-05
      • 1970-01-01
      • 2016-11-11
      • 2019-04-25
      • 2017-09-27
      • 2015-03-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多