Rest标准:路径参数或请求参数

51

我正在创建一个新的REST服务。

在Java中的不同REST实现中,传递参数的标准是什么?您可以将参数配置为路径的一部分或请求参数的形式。例如:

路径参数: http://www.rest.services.com/item/b

请求参数: http://www.rest.services.com/get?item=b

有人知道每种方法传递参数的优缺点吗?似乎将参数作为路径的一部分更符合REST协议的概念。也就是说,单个位置表示唯一的响应,对吗?


这个回答解决了你的问题吗?在RESTful API中何时使用路径参数和查询参数? - Archmede
我希望他们没有等待10年才看到这个评论! - dading84
6个回答

44

通常情况下,路径会被缓存,而参数则不会被缓存。

因此...

GET /customers/bob

对比

GET /customers?name=bob

前者更可能被缓存(假设使用了适当的头信息等),而后者则很可能不会被缓存。


你的查询参数示例并不是一个有效的示例。请查看这个问题:https://dev59.com/7l0Z5IYBdhLWcg3w4jdy - Archmede

35

简短概括: 也许你都需要。


第42项存在:

GET /items/42
Accept: application/vnd.foo.item+json
--> 200 OK
{
    "id": 42,
    "bar": "baz"
}

GET /items?id=42
Accept: application/vnd.foo.item-list+json
--> 200 OK
[
    {
        "id": 42,
        "bar": "baz"
    }
]

第99个项目不存在:

GET /items/99
Accept: application/vnd.foo.item+json
--> 404 Not Found

GET /items?id=99
Accept: application/vnd.foo.item-list+json
--> 200 OK
[
]

解释与评论

  1. /items/{id} 返回一个 item,而 /items?id={id} 则返回一个 item-list
  2. 即使在过滤后的 item-list 中只有一个元素,为了保持一致性 (而不是单个元素本身),仍将返回一个包含单个元素的列表。
  3. 碰巧的是,id 是一个唯一的属性。如果我们根据其他属性进行筛选,则仍然可以以完全相同的方式工作。
  4. 集合资源的元素只能使用唯一属性(例如作为集合的子资源的键)来命名,这是显而易见的原因(它们是普通资源,URI 唯一地标识资源)。
  5. 如果在使用筛选器时未找到元素,则响应仍为 OK,并且仍包含一个列表(尽管为空)。仅因为我们请求一个包含不存在的项的筛选列表,并不意味着列表本身不存在。

由于它们非常不同且独立有用,您可能都需要。客户端将希望区分所有情况(例如列表是否为空,或者列表本身不存在,在这种情况下,您应该/items?... 返回404)。

免责声明:这种方法绝不是“标准的”。但对我来说非常有意义,所以我感觉值得分享。

PS:将项目集合命名为“get”是一种编码上的问题;最好使用“items”或类似名称。


1
很棒的答案,详细阐述了资源位置和资源服务之间的关键区别。 - bishop

8

你提供的第二个“请求参数”的例子是不正确的,因为“get”包含在路径中。GET是请求类型,不应该作为路径的一部分。

有四种主要类型的请求:

 GET
 PUT
 POST
 DELETE

GET请求应该始终能够在没有任何请求体信息的情况下完成。此外,GET请求应该是“安全”的,这意味着请求不会修改任何重要数据。

除了上面提到的缓存问题之外,URL路径中的参数往往是必需的或者被期望的,因为它们也是路由的一部分,而在查询字符串中传递的参数更加变化,不影响请求路由到应用程序的哪个部分。虽然你可能还可以通过URL传递一个可变长度的参数集:

GET somedomain.com/states/Virginia,California,Mississippi/

一本关于这个主题的入门好书是"Restful Web Services"。但我要提醒你准备略过一些冗余信息。


4
Get并不是指HTTP方法,而是一个服务操作。 - onejigtwojig

4
我认为这取决于具体情况。一个资源对应一个URL。如果你想以稍微不同的方式接收该资源,可以使用查询字符串。但是,如果某个值会提供不同的资源,则将其放在路径中更合适。
所以,在你的例子中,变量的值直接关系到返回的资源。因此,将其放在路径中更有意义。

3
第一种变化更加简洁,可以将请求参数保留用于排序和分页等功能,例如:
http://www.rest.services.com/items/b?sort=ascending;page=6

0

这是一个很好的基本问题。我最近得出结论,要避免使用路径参数。它们会导致模糊的资源解析。URL 基本上是运行在服务器某处的代码片段的“方法名”。我不喜欢将变量名与方法名混合在一起。你的方法名称显然是“customer”(在我看来,这是一种糟糕的方法名称,但 REST 人士喜欢这种模式)。传递到该方法的参数是客户的姓名。查询参数对此非常有效,如果需要,甚至可以缓存此资源和查询参数值。

没有实际的 IT 客户资源。可能在以客户命名的文件夹下没有名为客户的文件。这是一个执行某种数据库事务的 Web 服务。“资源”是您的服务,而不是客户。

对 REST 和 Web 动词的着迷让我想起了面向对象编程的早期,我们试图将代码塞入物理对象的虚拟表示中。然后我们意识到,对象通常是系统中的虚拟概念。如果正确使用,面向对象编程仍然很有用。REST 也很有用,如果你认识到 RESTful 资源是服务,而不是对象。


5
我认为这个想法与目标相去甚远,将讨论引向了古老的RPC风格接口。在一个资源导向的世界里,你的URL不是一个方法名,而是资源的位置。你的“客户”绝对不是一个方法,而是该资源的名称。你的“方法”是服务墙后面的实现细节。你通过理解HTTP语义的服务来接口资源。这些是你要寻找的基础知识。 - K. Alan Bates

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接