在 REST 中,当资源被分页时,应该如何处理对 findAll 操作的 GET 请求?

发布于 2025-01-04 13:50:26 字数 773 浏览 2 评论 0原文

在 RESTful 服务中,无法一次全部检索的资源会被分页。例如:

GET /foo?page=1

问题是,我应该如何处理 getAll 请求,例如:
GET /foo

考虑到可发现性/HATEOAS,我看到了几个选项:

  1. 返回 405 Method Not allowed 并在首页包含一个 Link 标头: Link=; rel=”first“
  2. 返回 400 Bad Request 并包含链接标头(与上面相同)
  3. 返回 303 See Other 到第一个分页页面
  4. 返回200 OK 但实际上只返回第一页(并将下一页的 URI 包含到链接中): Link=; rel =“下一个”
    • 注意:我宁愿不这样做,因为我知道如果客户没有明确要求,默认情况下不会为客户管理任何事情。

这些当然只是一些选择。我倾向于第一种,但我不确定是否有我不知道的最佳实践。 如有任何反馈,我们将不胜感激。 谢谢。

In a RESTful Service, Resources that cannot all be retrieved at once are paginated. For example:

GET /foo?page=1

The question is, how should I handle a getAll request such as:
GET /foo

Taking discoverability/HATEOAS into consideration, I see a few options:

  1. return a 405 Method Not Allowed and include a Link header to the first page:
    Link=<http://localhost:8080/rest/foo?page=0>; rel=”first“
  2. return a 400 Bad Request and include the Link header (same as above)
  3. return a 303 See Other to the first paginated page
  4. return a 200 OK but actually return only the first page (and include the URI of the next page into the Link):
    Link=<http://localhost:8080/rest/foo?page=1>; rel=”next“

    • note: I would rather not do this, having learned not to manage anything for the client by default, if they haven't explicitly asked for it.

These are of course only a few options. I'm leaning towards the first, but I'm not sure if there is a best practice on this that I am not aware of.
Any feedback is appreciated.
Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

生来就爱笑 2025-01-11 13:50:26

让我们首先了解一个事实:REST 并不是像 SOAP 那样的一成不变的协议,它只是一种构造服务的方法,类似于语言被描述为面向对象的方式。

综上所述,我建议按如下方式处理。


将 RESTful 调用视为函数声明。

GET /foo
foo()

有些函数需要参数。

GET /foo?start=??&count=??
foo(start, count)

有些语言支持默认参数,有些则不支持;您可以自己决定如何处理参数。

使用默认参数,您可以假设该函数被定义为

foo(start = 0, count = 10)

GET /foo 的调用实际上相当于 GET /foo?start=0&count=10 >,而调用 GET /foo?start=100 相当于 GET /foo?start=100&count=10

如果您想要默认参数,您可以强制 API 用户显式设置 startcount

foo(start, count)

以便调用GET /foo 将返回 400 Bad Request 状态代码,但调用 GET /foo?start=0&count=10 将返回200 OK 状态代码以及包含的内容按指定范围。

在任何一种情况下,您都必须决定如何处理错误,例如

GET /foo?start=-10&count=99999999

如果参数有最大值和最小值,您将需要决定是规范化参数,还是简单地返回错误。前面的示例可能会返回 400 Bad Request 状态代码,但它也可能会被限制为:

GET /foo?start=0&count=1000

最后由您决定什么在您的应用程序上下文中最有意义。

Lets start with the fact that REST is not a set-in-stone protocol like SOAP, it's simply a means of structuring a service, similar to how languages are described as being Object-Oriented.

That all being said, I'd recommend the handling this as follows.


Treat a RESTful call like a function declaration.

GET /foo
foo()

Some functions require parameters.

GET /foo?start=??&count=??
foo(start, count)

Some languages support default parameters, others don't; you get to decide for yourself how you want to handle parameters.

With default parameters, you could assume that the function was defined as

foo(start = 0, count = 10)

so that a call to GET /foo would actually be equivalent to GET /foo?start=0&count=10, whereas a call to GET /foo?start=100 would be equivalent to GET /foo?start=100&count=10.

If you don't want default parameters, you could force the user of the API to explicitly set start and count:

foo(start, count)

so that a call to GET /foo would return a 400 Bad Request status code, but a call to GET /foo?start=0&count=10 would return a 200 OK status code along with the content contained by the specified range.

In either case you'll have to decide how you'll handle errors, such as

GET /foo?start=-10&count=99999999

If parameters have maximums and minimums, you'll need to decide whether to normalize the parameters, or simply return errors. The previous example might return a 400 Bad Request status code, but it could also be constrained to turn into:

GET /foo?start=0&count=1000

In the end it's up to you to decide what makes the most sense in the context of your application.

夜声 2025-01-11 13:50:26

从 RESTful 的角度来看,我认为以相同的方式处理这两种表示是完全可以的。考虑一个您想要下载的有多个版本的软件,最新的版本是 3.8。因此,如果您想获取最新版本,可以使用 GET /software/version/latest.zip 和 GET /software/version/3.8.zip 来解决,直到有一个更新的版本。因此两个不同的链接指向同一个资源。

我喜欢想象分页几乎是一样的。第一页总是有最新的文章。因此,如果没有提供 page 参数,您可以简单地暗示它是 1。

使用 rel 属性的方法的方向略有不同。它是 Google 为更好地处理重复内容问题而创建的,主要用于区分“主”页面和分页页面。以下是如何使用它:

//first page:
<link rel="next" href="http://www.foo.com/foo?page=2" />

//second page:
<link rel="prev" href="http://www.foo.com/foo?page=1" />
<link rel="next" href="http://www.foo.com/foo?page=3" />

//third and last page:
<link rel="prev" href="http://www.foo.com/foo?page=2" />

因此,从 SEO 的角度来看,使用这些元素是一个好主意(并且由 Google 推荐)。它们还与 REST 的面向资源的思想和资源的超媒体表示完美契合。

选择您的建议之一,我认为 303 See Other 是正确的选择。它旨在用于此类目的,并且是规范化资源的好方法。您可以通过许多 URI 来提供它们,但只有一个“真实”URI 来表示(就像具有不同版本的软件)。

根据规范,响应应如下所示:

303 See Other
Location: http:www.foo.com/foo?page=1

<a href="http:www.foo.com/foo?page=1">http:www.foo.com/foo?page=1</a>

因此,您提供具有“真实”表示形式的位置标头,并且正文应包含链接到新 URI 的超文本文档。请注意,根据规范,客户端预期向位置值发送 GET 请求,但实际上并非必须


//编辑作为对您评论的回答(是的,在没有证明的情况下声称某些东西是非常糟糕的做法:-) - 我的错!):

Google 提出了 rel="next" 和 rel="prev" 属性于 2011 年 9 月在 官方网站站长中心博客。它们还可以额外用于(或在某些情况下代替)rel="canonical" 标签

在这些链接下,您可以找到它们之间的差异解释:

  • rel="next"rel="prev" 链接元素 是“指示分页系列中组件 URL 之间的关系”
  • rel="canonical" “允许您公开指定您首选的 URL 版本”,

因此它们之间存在细微差别。因此,您可以将问题分解为规范问题:有多个 URL 指向同一资源(/foofoo?page=1 但您有一个首选版本URL 的 (foo?page=1),现在有一些 RESTful 方法的选项:

  • 如果查询中没有给出 page 参数,请使用我认为处理它时有一个默认值(例如1)。 即使您指出这是不好的做法,也可以使用默认值。
  • 在这种特定情况下, .3.4" rel="nofollow">303 See OtherLocation 标头中提供首选 URL(如所述 是处理重复/规范内容的最佳方式(并且很可能是 REST 方式)。
  • 我认为 3xx响应 org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1" rel="nofollow">400 错误请求以防万一想要强制客户端提供一个 page 参数(如 zzzzBov 在他的回答中所解释的)。请注意,此响应没有诸如位置标头之类的内容(如您的问题中假设的那样),因此请求失败的原因和/或正确的URL(如果给出)的解释) 必须转到响应的实体主体。另请注意,根据规范,当客户端提交错误/格式错误的表示(!不是 URL!)以及 PUTPOST 请求时,通常会使用此响应。因此请记住,这对于客户来说也可能有点模糊。

就我个人而言,我不认为您建议使用 进行响应405 Method Not allowed 是个好主意。根据规范,您必须提供一个Allow标头,列出允许的方法。但是该资源可以使用哪些方法呢?我只能想到POST。但是,如果您也不希望客户端POST到它,您也可以使用 403 Forbidden 并解释为什么禁止它,或 404 Not Found 如果您不想说出为什么它被禁止。所以它也可能有点模棱两可(在我看来)。

正如您在问题中提出的那样,将 link-elements 与提到的 rel-attributes 一起使用本质上并不是“RESTful”,因为它只是在资源表示中解决的超媒体。但您的问题(据我了解)是您想要决定如何响应特定请求以及服务哪个表示。但这仍然不是绝对没有意义的:

您可以将整个 SEO 问题视为使用 rel="next/prev/canonical" 的副作用,但请记住,它们也会创建连接性< /em> (作为链接的质量)这是 REST 的特征之一(参见 罗伊·菲尔丁的论文)。

如果您想深入研究 RESTful Web 服务(这是完全值得的),我建议您阅读这本书RESTful Web 服务 作者:Leonard Richardson 和 Sam红宝石。

From a RESTful point of view, I think it perfectly alright to handle both representations the same. Consider a software with several versions you want to download, the latest one being 3.8. So if you want to get the latest version, you could address it with both GET /software/version/latest.zip and GET /software/version/3.8.zip until there comes a newer version. So two different links point to the same resource.

I like to imagine pagination pretty much the same. On the first page there are always the latest articles. So if no page-parameter is provided, you could simply imply it's 1.

The approach with the rel attribute goes in a slightly different direction. It's a creation of Google to better handle the problem with duplicate content and is primarily considered to be used in order to distinguish between a "main" page and pagination-pages. Here's how to use it:

//first page:
<link rel="next" href="http://www.foo.com/foo?page=2" />

//second page:
<link rel="prev" href="http://www.foo.com/foo?page=1" />
<link rel="next" href="http://www.foo.com/foo?page=3" />

//third and last page:
<link rel="prev" href="http://www.foo.com/foo?page=2" />

So from a SEO point of view it's a good idea (and recommended by Google) to use those elements. They also go perfectly with the resource-orientated idea of REST and the hypermedia representation of the resources.

Choosing one of your suggestions, I think the 303 See Other is the right way to go. It was intended to be used for this kind of purposes and is a good way to canonicalize your resources. You can make them available through many URIs, but have one "real" URI for a representation (like the software with different versions).

According to the specification, the response should look something like this:

303 See Other
Location: http:www.foo.com/foo?page=1

<a href="http:www.foo.com/foo?page=1">http:www.foo.com/foo?page=1</a>

So you provide a Location-header with the "real" representation, and the body should contain a hypertext document linking to the new URI. Note that according to the specification the client is expected to send a GET request to the value of Location, but it doesn't have to.


//EDIT as answer to your comment (yep, it's really bad practice to claim something without proving it :-) - my bad!):

Google presented the rel="next" and rel="prev" attributes in September 2011 on the Official Webmaster Central Blog. They can be used additionally to (or in some cases instead of) the rel="canonical" tag.

Under those links you can find the differences between them explained:

  • rel="next" and rel="prev" link elements are "to indicate the relationship between component URLs in a paginated series"
  • the rel="canonical" "allows you to publicly specify your preferred version of a URL"

So there is a slight difference between them. So you can break down your problem to a canonical issue: There are several URLs pointing to the same resource (/foo and foo?page=1 but you have a preferred version of the URL (foo?page=1). So now there are a few options for a RESTful approach:

  • If there is no page-parameter given in the query, use a default value (e.g. 1) when processing it. I think in this specific case it is OK to use a default value even though you point it out as bad practice.
  • Respond with 303 See Other providing the preferred URL in the Location-header (as described above). I think a 3xx-response is the best (and most likely RESTfully intended) way to deal with duplicate/canonical content.
  • Respond with 400 Bad Request in case you want to force the client to provide a page-parameter (as explained by zzzzBov in his answer). Note that this response does not have something like a Location header (as assumed in your question), so the explanation why the request failed and/or the correct URL (if given) must go to the entity-body of the response. Also, note that according to the specification this response is commonly used when the client submits a bad/malformed representation (! not URL !) along with a PUT or POST request. So keep in mind that this also might be a little ambiguous for the client.

Personally, I don't think your suggestion to respond with 405 Method Not Allowed is a good idea. According to the specification, you must provide an Allow-header listing the allowed methods. But what methods could be allowed on this resource? I can only think of POST. But if you do not want the client to POST to it either, you could also respond with 403 Forbidden with an explanation why it is forbidden, or 404 Not Found if you do not want to tell why it is forbidden. So it might be a little ambiguous, too (in my opinion).

Using link-elements with the mentioned rel-attributes as you propose in your question is not essentially 'RESTful' because it's only hypermedia which is settled in the representation of the resource. But your problem (as far as I understand it) is that you want to decide how to respond to a specific request and which representation to serve. But still it's not absolutely pointless:

You can consider the whole SEO issue as a side effect of using rel="next/prev/canonical", but keep in mind that they also create connectedness (as the quality of having links) which is one of the characteristics of REST (see Roy Fielding's dissertation).

If you want to dive into RESTful Web Services (which is totally worth it) I recommend reading the book RESTful Web Services by Leonard Richardson and Sam Ruby.

原来分手还会想你 2025-01-11 13:50:26

在某些情况下,不隐式地为客户端管理任何内容可能会导致覆盖复杂的界面,例如消费者不具备技术能力或不打算在界面之上构建的情况,例如在网页中。在这种情况下,甚至 200 也可能是合适的。

在其他情况下,我同意隐式管理是一个坏主意,因为消费者希望能够正确预测响应,并且可能需要简单的规范。在这种情况下,405、400 和 303。

这是一个上下文问题。

In some cases not implicitly managing anything for the client can lead to a overlay complex interface, examples would be where the consumer isn't technical or isn't intending on building on top of interface, for example in a web page. In such cases even a 200 may be appropriate.

In other cases I would agree implicit management would be a bad idea as the where a consumer would want to be able to predict the response correctly and where a simple specification may be required. In such cases 405, 400 and 303.

It's a matter of context.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文