【问题标题】:When to use @QueryParam vs @PathParam何时使用 @QueryParam 与 @PathParam
【发布时间】:2012-07-19 00:18:57
【问题描述】:

我不是在问这里已经问过的问题: What is the difference between @PathParam and @QueryParam

这是一个“最佳实践”或约定问题。

你什么时候使用@PathParam vs @QueryParam

我能想到的决定可能是使用两者来区分信息模式。让我在下面说明我的 LTPO - 不太完美的观察。

PathParam 的使用可以保留给信息类别,它可以很好地落入信息树的一个分支中。 PathParam 可用于深入了解实体类层次结构。

而 QueryParam 可以保留用于指定属性以定位类的实例。

例如,

  • /Vehicle/Car?registration=123
  • /House/Colonial?region=newengland

/category?instance

@GET
@Path("/employee/{dept}")
Patient getEmployee(@PathParam("dept")Long dept, @QueryParam("id")Long id) ;

/category/instance

@GET
@Path("/employee/{dept}/{id}")
Patient getEmployee(@PathParam("dept")Long dept, @PathParam("id")Long id) ;

?category+instance

@GET
@Path("/employee")
Patient getEmployee(@QueryParam("dept")Long dept, @QueryParam("id")Long id) ;

我认为没有标准的惯例。有没有?但是,我想听听人们如何使用 PathParam 与 QueryParam 来区分他们的信息,就像我上面举例说明的那样。我也很想听听这种做法背后的原因。

【问题讨论】:

标签: java rest jax-rs


【解决方案1】:

REST 可能不是这样的标准,但阅读一般 REST 文档和博客文章应该可以为您提供一些指导,以便更好地构建 API URL。大多数 REST API 往往在路径中只有资源名称和资源 ID。如:

/departments/{dept}/employees/{id}

一些 REST API 使用查询字符串进行过滤、分页和排序,但由于 REST 不是一个严格的标准,我建议检查一些 REST API,例如 githubstackoverflow 看看哪些可以很好地工作对于您的用例。

我建议将任何必需的参数放在路径中,任何可选参数当然应该是查询字符串参数。在尝试编写匹配不同组合的 URL 处理程序时,将可选参数放在路径中最终会变得非常混乱。

【讨论】:

  • "我建议将任何必需的参数放在路径中,任何可选参数当然应该是查询字符串参数。" - 竖起大拇指 +1 是 def
  • 是否也应该将此约定用于 Put 请求,假设我们要更新特定版本的 db 实体,URI 应该是 PUT /depatments/{dept}/employees/{id}/{version} 并且版本是可选的还是应该是 PUT /depatments/{dept}/employees/{id}?version=12和版本是可选的
  • 在这种情况下,我会建议: - PUT /depatments/{dept}/employees/{id}/versions/{version} 创建具有所选版本的员工 - POST /depatments/{dept}/employees/{id}/versions 创建具有由后端确定的版本的员工
【解决方案2】:

这就是我的工作。

如果有根据id检索记录的场景,例如需要获取id为15的员工的详细信息,则可以通过@PathParam获取资源。

GET /employee/{id}

如果您需要获取所有员工的详细信息,但一次只能获取 10 个,您可以使用查询参数

GET /employee?start=1&size=10

这表示起始员工 id 1 有 10 条记录。

总而言之,使用@PathParam 进行基于id 的检索。用户 @QueryParam 用于过滤,或者如果您有任何用户可以通过的固定选项列表。

【讨论】:

  • '@PathParam' 和 '@QueryParam' 是否提供相同的功能? '@QueryParam' 只是写同一件事的另一种方式吗?
  • @RishabhAgarwal 尽管两者都提供相同的功能,但干净的代码做法是,建议将必需参数作为路径变量,将任何可选参数作为查询参数。
  • @RishabhAgarwal 更多信息可以参考我的文章Rest API Best Practices
【解决方案3】:

我认为,如果参数标识特定实体,您应该使用路径变量。例如,要获取我请求的博客上的所有帖子

GET: myserver.com/myblog/posts

要获得 id = 123 的帖子,我会要求

GET: myserver.com/myblog/posts/123

但要过滤我的帖子列表并获取自 2013 年 1 月 1 日以来的所有帖子,我会要求

GET: myserver.com/myblog/posts?since=2013-01-01

在第一个示例中,“帖子”标识了一个特定实体(整个博客帖子集合)。在第二个示例中,“123”还表示特定实体(单个博客文章)。但在最后一个示例中,参数“since=2013-01-01”是过滤帖子集合而不是特定实体的请求。分页和排序是另一个很好的例子,即

GET: myserver.com/myblog/posts?page=2&order=backward

希望对您有所帮助。 :-)

【讨论】:

    【解决方案4】:

    我个人使用的方法是“如果用户将包含这些参数的 URL 加入书签有意义,则使用 PathParam”。

    例如,如果用户配置文件的 URL 包含一些配置文件 id 参数,因为这可以由用户添加书签和/或通过电子邮件发送,我将包含该配置文件 id 作为路径参数。此外,另一个考虑因素是包含路径参数的 URL 表示的页面不会改变——用户将设置他/她的个人资料,保存它,然后不太可能从那里改变那么多;这意味着网络爬虫/搜索引擎/浏览器/等可以根据路径很好地缓存此页面。

    如果在 URL 中传递的参数可能会更改页面布局/内容,那么我会将其用作查询参数。例如,如果配置文件 URL 支持指定是否显示用户电子邮件的参数,我会认为这是一个查询参数。 (我知道,可以说,你可以说&noemail=1 或它的任何参数都可以用作路径参数并生成 2 个单独的页面——一个带有电子邮件,一个没有它——但从逻辑上讲,这不是案例:它仍然是显示或不显示某些属性的同一页面。

    希望这会有所帮助——我很欣赏解释可能有点模糊 :)

    【讨论】:

    • 我认为这个答案混淆了资源和路线。问题是关于 REST API 的资源,通常返回 JSON 或 XML,而不是关于帮助您在应用程序中导航的 Web 应用程序的路由。
    【解决方案5】:

    您可以使用查询参数进行过滤,使用路径参数进行分组。以下链接有关于这个When to use pathParams or QueryParams的好信息

    【讨论】:

      【解决方案6】:

      这是一个非常有趣的问题。

      你可以同时使用它们,这个主题没有任何严格的规定,但是使用 URI 路径变量有一些优点:

      • 缓存: Internet 上的大多数 Web 缓存服务在包含查询参数时都不会缓存 GET 请求。 他们这样做是因为有很多 RPC 系统使用 GET 请求来更改服务器中的数据(失败!!Get 必须是一种安全的方法)

      但如果你使用路径变量,所有这些服务都可以缓存你的 GET 请求。

      • 层次结构: 路径变量可以表示层次结构: /城市/街道/地点

      它为用户提供了有关数据结构的更多信息。

      但如果您的数据没有任何层次关系,您仍然可以使用路径变量,使用逗号或分号:

      /城市/经度,纬度

      原则上,参数的顺序重要时使用逗号,不重要时使用分号:

      /IconGenerator/red;blue;green

      除了这些原因,在某些情况下使用查询字符串变量很常见:

      • 当您需要浏览器自动将 HTML 表单变量放入 URI 时
      • 在处理算法时。例如 google 引擎使用查询字符串:

      http://www.google.com/search?q=rest

      总而言之,没有任何充分理由使用其中一种方法,但只要可以,请使用 URI 变量。

      【讨论】:

        【解决方案7】:

        From Wikipedia: Uniform Resource Locator

        路径,其中包含数据,通常以分层形式组织,显示为由斜线分隔的一系列段。

        可选查询,用问号 (?) 与前一部分分隔,包含非分层数据的查询字符串

        ——根据 URL 的概念设计,我们可以为分层数据/指令/定位器组件实现 PathParam,或者在数据不分层时实现 QueryParam。这是有道理的,因为路径是自然排序的,而查询包含可以任意排序的变量(无序的变量/值对)。

        一位之前的评论者写道,

        我认为如果参数标识了一个特定的实体,你应该使用路径变量。

        另一位写道,

        使用@PathParam 进行基于id 的检索。用户 @QueryParam 用于过滤,或者如果您有任何用户可以通过的固定选项列表。

        另一个,

        我建议将任何必需的参数放在路径中,任何可选参数当然应该是查询字符串参数。

        ——然而,人们可能会实施一种灵活的、非分层的系统来识别特定实体!一个人可能在一个 SQL 表上有多个唯一索引,并允许使用构成唯一索引的字段的任意组合来识别实体!不同的组合(可能也以不同的顺序排列)可能用于来自各种相关实体(引用者)的链接。在这种情况下,我们可能正在处理用于识别单个实体的非分层数据——或者在其他情况下,可能只指定某些变量/字段——唯一索引的某些组件——并检索一个列表/一组记录。在这种情况下,将 URL 实现为 QueryParams 可能更容易、更合乎逻辑和更合理!

        一个长的十六进制字符串会稀释/减少路径其余部分中关键字的值吗?这可能值得considering the potential SEO implications of placing variables/values in the path, or in the query,以及我们是否希望用户能够通过编辑地址栏的内容来遍历/探索 URL 的层次结构的人机界面含义。我的 404 Not Found 页面使用 SSI 变量自动将损坏的 URL 重定向到其父级!搜索机器人也可能遍历路径层次结构。 另一方面,就我个人而言,当我在社交媒体上分享 URL 时,我会手动删除任何私有的唯一标识符——通常是通过截断 URL 中的查询,只留下路径:在这种情况下,放置唯一标识符有一些实用性在路径中而不是在查询中。我们是否想促进将路径组件用作粗略的用户界面,可能取决于数据/组件是否是人类可读的。人类可读性问题在某种程度上与层次结构问题有关:通常,可以表示为人类可读关键字的数据也是层次结构的;而分层数据通常可以表示为人类可读的关键字。 (搜索引擎本身可能被定义为增加 URL 作为用户界面的使用。)关键字或指令的层次结构可能没有严格排序,但它们通常足够接近,我们可以覆盖路径中的其他情况,@987654323 @。

        对于每个请求,我们可以通过 URL 回答基本上几种问题:

        1. 我们请求/提供什么样的记录/东西?
        2. 我们对哪些感兴趣?
        3. 我们希望如何呈现信息/记录?

        几乎可以肯定,Q1 最好由路径或 PathParams 覆盖。 Q3(可能通过一组任意排序的可选参数和默认值来控制);几乎可以肯定 QueryParams 覆盖得最好。 Q2:这取决于……

        【讨论】:

          【解决方案8】:

          正如theon 所说,REST 不是标准。但是,如果您希望实现基于标准的 URI 约定,则可以考虑使用oData URI convention。版本 4 一直是 approved as an OASIS standard,并且通过 Apache Olingo 存在用于各种语言(包括 Java)的 oData 库。不要因为它是微软的产物而让您失望,因为它是 gained support from other industry player's as well,其中包括 Red Hat、Citrix、IBM、Blackberry、Drupal、Netflix Facebook 和 SAP

          More adopters are listed here

          【讨论】:

            【解决方案9】:

            您可以同时支持查询参数和路径参数,例如,在资源聚合的情况下——当子资源的集合本身就有意义时。

            /departments/{id}/employees
            /employees?dept=id
            

            查询参数可以支持分层和非分层子集;路径参数仅是分层的。

            资源可以表现出多个层次结构。如果您要查询跨层次边界的广泛子集合,请支持短路径。

            /inventory?make=toyota&model=corolla
            /inventory?year=2014
            

            使用查询参数来组合正交层次结构。

            /inventory/makes/toyota/models/corolla?year=2014
            /inventory/years/2014?make=toyota&model=corolla
            /inventory?make=toyota&model=corolla&year=2014
            

            在组合的情况下仅使用路径参数——当资源与其父级分离时没有意义,并且所有子级的全局集合本身不是有用的资源。

            /words/{id}/definitions
            /definitions?word=id   // not useful
            

            【讨论】:

              【解决方案10】:

              在谈论 QueryParam 和 PathParam 之前。让我们首先了解 URL 及其组件。 URL 由端点 + 资源 + queryParam/ PathParam 组成。

              例如,

              URL: https://app.orderservice.com/order?order=12345678
              

              URL: https://app.orderservice.com/orders/12345678
              

              在哪里

              端点:https://app.orderservice.com

              资源:订单

              查询参数:order=12345678

              路径参数:12345678

              @QueryParam:

              QueryParam 用于根据特定条件/条件过滤请求时使用。标准用 ?在 URL 中的资源之后。可以在queryParam中使用&符号指定多个过滤条件。

              例如:

              https://app.orderservice.com/orders?order=12345678 & customername=X

              @PathParam:

              当需要根据 guid/id 选择特定订单时使用 PathParam。 PathParam 是 URL 中资源的一部分。

              例如:

              https://app.orderservice.com/orders/12345678

              【讨论】:

              • 真的很喜欢你的解释。
              【解决方案11】:

              路径参数 - 路径参数是 URL 路径中的一个变量,有助于指向一些特定的资源。

              Example - https://sitename.com/questions/115
              

              在这里,如果 115 是一个路径参数,则可以将其更改为其他有效数字以获取/指向同一应用程序上的其他资源。

              查询参数 - 查询参数是 URL 路径中的变量,用于过滤列表中的某些特定资源。

              Example - https://sitename.com/questions/115?qp1=val1&qp2=val2&qp3=val3
              

              这里的 qp1、qp2 和 qp3 是查询变量,它们的值分别为 val1、val2 和 val3。这些可用于在获取/保存我们的数据时用作过滤器。查询变量总是附加在 URL 中的问号 (?) 之后。

              【讨论】:

                【解决方案12】:

                原因其实很简单。使用查询参数时,您可以输入诸如“/”之类的字符,并且您的客户端不需要对它们进行 html 编码。还有其他原因,但这是一个简单的例子。至于何时使用路径变量。我会说,每当您处理 id 或路径变量是查询的方向时。

                【讨论】:

                  【解决方案13】:

                  我举一个例子来说明我们什么时候使用@Queryparam@pathparam

                  例如我正在服用一个资源是carResource class

                  如果你想强制你的资源方法的输入,那么使用参数类型为@pathaparam,如果你的资源方法的输入应该是可选的,那么保持参数类型为@QueryParam参数

                  @Path("/car")
                  class CarResource
                  {
                      @Get
                      @produces("text/plain")
                      @Path("/search/{carmodel}")
                      public String getCarSearch(@PathParam("carmodel")String model,@QueryParam("carcolor")String color) {
                          //logic for getting cars based on carmodel and color
                              -----
                          return cars
                      }
                  }
                  

                  为此资源传递请求

                  req uri ://address:2020/carWeb/car/search/swift?carcolor=red
                  

                  如果你像这样给出 req,resouce 将给出基于的汽车型号和颜色

                   req uri://address:2020/carWeb/car/search/swift
                  

                  如果你像这样给出 req,resoce 方法将只显示基于 swift 模型的汽车

                  req://address:2020/carWeb/car/search?carcolor=red
                  

                  如果你这样给出,我们将得到 ResourceNotFound 异常,因为在汽车资源类中,我将汽车模型声明为@pathPram,这是你必须并且应该将汽车模型作为 reQ uri 否则它不会将 req 传递给资源,但如果你不要传递颜色,它也会将req传递给资源为什么因为颜色是@quetyParam它在req中是可选的。

                  【讨论】:

                    【解决方案14】:
                    1. @QueryParam 可以方便地与 Default Value 注解配合使用,这样可以避免在没有传入查询参数的情况下出现空指针异常。

                    当您想从 GET 请求中解析查询参数时,您可以简单地为将处理 GET 请求的方法定义相应的参数并使用 @QueryParam 注释对其进行注释

                    1. @PathParam 提取 URI 值并匹配到 @Path。因此得到输入参数。 2.1 @PathParam可以不止一个,并且设置为方法参数

                      @Path("/rest")
                      public class Abc {
                      
                          @GET
                          @Path("/msg/{p0}/{p1}")
                          @Produces("text/plain")
                          public String add(@PathParam("p0") Integer param1, @PathParam("p1")  Integer param2 )
                          {
                              return String.valueOf(param1+param2);
                          }
                      } 
                      

                    在上面的示例中,
                    http://localhost:8080/Restr/rest/msg/{p0}/{p1},
                    p0 匹配 param1p1 匹配 param2。所以对于 URI
                    http://localhost:8080/Restr/rest/msg/4/6,
                    我们得到结果10

                    在 REST 服务中,JAX-RS 提供了@QueryParam@FormParam 来接受来自 HTTP 请求的数据。 HTTP 表单可以通过 GET 和 POST 等不同的方法提交。

                    @QueryParam:接受 GET 请求并从查询字符串中读取数据。

                    @FormParam:接受 POST 请求并从 HTML 表单或媒体的任何请求中获取数据

                    【讨论】:

                      【解决方案15】:

                      简而言之,

                      @Pathparam 适用于通过资源和查询字符串传递的值

                      • /user/1
                      • /user?id=1

                      @Queryparam 仅用于传递查询字符串的值

                      • /user?id=1

                      【讨论】:

                        【解决方案16】:

                        对于资源名称和 ID,我使用 @PathParams。对于可选变量,我使用@QueryParams

                        【讨论】:

                          【解决方案17】:

                          据我了解:

                          1. 使用@PathParam - 当它是强制性项目时,例如 Id

                            GET /balloon/{id}

                          2. 使用@QueryParam - 当您拥有确切的资源但需要根据一些可选特征(例如颜色、大小等)对其进行过滤时。

                            GET /balloon/123?color=red&size=large

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 2018-06-29
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2012-05-12
                            • 1970-01-01
                            相关资源
                            最近更新 更多