设计带有一长串查询参数的 RESTful 查询 API [关闭]

Posted

技术标签:

【中文标题】设计带有一长串查询参数的 RESTful 查询 API [关闭]【英文标题】:Design RESTful query API with a long list of query parameters [closed] 【发布时间】:2012-12-21 13:18:39 【问题描述】:

我需要设计一个 RESTful 查询 API,它根据几个过滤器返回一组对象。通常的 HTTP 方法是 GET。唯一的问题是,它至少可以有十几个过滤器,如果我们将它们全部作为查询参数传递,URL 可能会变得很长(长到足以被某些防火墙阻止)。

减少参数的数量不是一种选择。

我能想到的另一种选择是在 URI 上使用 POST 方法,并将过滤器作为 POST 正文的一部分发送。这是否反对 RESTfull(发出 POST 调用以查询数据)。

谁有更好的设计建议?

【问题讨论】:

使用短的(1 字符等)参数名称? 它可能不是真正的 RESTful,但我认为在 GET 和 POST 方面你必须实用。如果你有那么多变量要发送并且你不能减少它们,我会发布它们。我不喜欢过度填充 URL,但这只是我自己。 谢谢。即使这个问题已经结束,这正是我需要回答的问题。我很高兴你问。 【参考方案1】:

请记住,对于 REST API,这完全取决于您的观点。

REST API 中的两个关键概念是端点和资源(实体)。简单地说,一个端点要么通过 GET 返回资源,要么通过 POST 和 PUT 等(或以上的组合)接受资源。

通过 POST,您发送的数据可能会或可能不会导致创建新资源及其关联的端点,这很可能不会在 POST 的 url 下“活动”,这是公认的。换句话说,当您发布时,您将数据发送到某处进行处理。 POST 端点不是通常可以找到资源的位置。

引用RFC 2616(不相关部分省略,相关部分突出显示):

9.5 发布

POST 方法用于请求源服务器接受 包含在请求中的实体作为资源的新下属 由 Request-Line 中的 Request-URI 标识。 POST 旨在 允许一个统一的方法覆盖以下功能:

... 向数据处理过程提供数据块,例如提交表单的结果; ...

...

POST 方法执行的操作可能不会产生可由 URI 识别的资源。在这种情况下,200(正常)或 204(无内容)是适当的响应状态,具体取决于响应是否包含描述结果的实体

如果在源服务器上创建了资源,则响应应该是 201 (Created)...

我们已经习惯了代表“事物”或“数据”的端点和资源,无论是用户、消息还是书籍——无论问题领域如何规定。但是,端点也可以公开不同的资源 - 例如搜索结果。

考虑以下示例:

GET    /books?author=AUTHOR
POST   /books
PUT    /books/ID
DELETE /books/ID

这是一个典型的 REST CRUD。但是,如果我们添加:

POST /books/search

    
        "keywords": "...",
        "yearRange": "from": 1945, "to": 2003,
        "genre": "..."
    

这个端点没有什么非 RESTful 的。它接受请求正文形式的数据(实体)。该数据就是搜索标准 - 与其他任何数据一样的 DTO。此端点响应请求生成资源(实体):搜索结果。搜索结果资源是一个临时资源,会立即提供给客户端,无需重定向,也不会暴露于其他一些规范的 url。

它仍然是 REST,除了实体不是书籍 - 请求实体是书籍搜索条件,响应实体是书籍搜索结果。

【讨论】:

您能推荐一些 DTO 的类命名约定吗? 我个人会选择BooksSearchCriteriaDTOBooksSearchResultsDTO 对于这种 POST /books/search 情况,最好的 HTTP 响应代码是什么? 201 仍然适用吗? 201 是相反的——它意味着已经创建了一个资源。预计在某处拥有自己唯一 URI 的资源。当POST 用于CRUD 的C 部分时,201 是合适的。我会使用普通的旧 200,也可以选择使用 204 作为空搜索结果。 请记住,现在 GET 在理论上也非常适用——“被称为“HTTP/1.1 规范”的 RFC2616 现在已过时。在 2014 年,它被 RFC 7230-7237 取代。引用“处理请求时应该忽略消息正文”已被删除。现在只是“请求消息框架独立于方法语义,即使该方法没有定义消息正文的任何​​用途”第二个引用“The GET 方法意味着检索任何由 Request-URI 标识的信息......“已删除。” - 来自***.com/questions/978061/http-get-with-request-body【参考方案2】:

很多人已经接受这样的做法,即查询字符串太长或太复杂(例如查询字符串不能轻松处理嵌套数据)的 GET 可以作为 POST 发送,而表示复杂/长数据在请求的正文中。

在 HTTP 规范中查找 POST 规范。它非常广泛。 (如果你想通过 REST 中的漏洞驾驶战舰……使用 POST。)

您失去了 GET 语义的一些好处……例如自动重试,因为 GET 是幂等的,但如果您能接受这一点,那么接受使用 POST 处理非常长或复杂的查询可能会更容易。

(lol 题外话...我最近发现,根据 HTTP 规范,GET 可以包含一个文档正文。有一段说,解释说,“任何请求都可以有一个文档正文,除了本节中列出的那些“......并且它所指的部分没有列出任何内容。我搜索并找到了一个HTTP作者正在谈论的线程,这是故意的,因此路由器等不会必须区分不同的消息。然而,在实践中,许多基础设施部分确实放弃了 GET 的主体。因此,您可以使用主体中表示的过滤器进行 GET,例如 POST,但您将掷骰子。)

【讨论】:

另请参阅this 问题以了解有关使用正文的 HTTP GET 的更多讨论。 很多人发明了一些不同于 RESTful 和 HTTP 规范的东西。 RESTful Fielding 的作者对此表示遗憾。【参考方案3】:

简而言之:创建一个 POST,但使用 X-HTTP-Method-Override 标头覆盖 HTTP 方法。

真实请求

发布/书籍

实体主体

"title": "Ipsum", “年份”:2017

标题

X-HTTP-Method-Override: GET

在服务器端,检查头 X-HTTP-Method-Override 是否存在,然后将其值作为方法来构建到后端最终端点的路由。此外,将实体主体作为查询字符串。从后端的角度来看,请求变成了一个简单的 GET。

通过这种方式,您可以使设计与 REST 原则保持一致。

编辑:我知道这个解决方案最初是为了解决某些浏览器和服务器中的 PATCH 动词问题,但它也适用于我的 GET 动词,因为 URL 很长,这是问题所在问题中描述。

【讨论】:

IETF 已弃用 X 前缀 HTTP 标头:tools.ietf.org/html/rfc6648 Google translate API POST request with X-HTTP-Method-Override @jannis 您链接的 RFC 保持 1.4。它对现有的 X- 删除和 1.5 没有任何建议。它不会覆盖现有规范。 ...X- IMO 会留在这里。【参考方案4】:

如果您使用 Java 和 JAX-RS 进行开发,我建议您使用 @QueryParam 和 @GET

当我需要查看列表时,我也有同样的问题。

查看示例:

import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/poc")
public class UserService 

    @GET
    @Path("/test/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@QueryParam("code") final List<Integer> code) 
                Integer int0 = codigo.get(0);
                Integer int1 = codigo.get(1);

        return Response.ok(new JSONObject().put("int01", int0)).build();
    

URI 模式: “poc/test?code=1&code=2&code=3

@QueryParam会自动将查询参数“orderBy=age&orderBy=name”转换成java.util.List。

【讨论】:

如果你解释你的例子会更好。它是用什么编程语言编写的? 嗨@AleksAndreev。谢谢您的意见。好转了吗? tks 这个问题是关于 RESTful 服务的设计,而不是关于实现。这个答案没有回答问题。 @user1331413 恕我直言,是的,现在更好了。感谢您的努力。但是,正如 Mike McCaughan 所说,问题是关于 REST 概念,而不是实现

以上是关于设计带有一长串查询参数的 RESTful 查询 API [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

WCF Restful 和带有特殊字符的查询字符串

Kafka Topic Partition Offset 这一长串都是啥?

java:一长串条件,怎么办? [关闭]

如何设计一个多条件查询的restfulAPI

更新表格以擦除一长串 html

验证一长串随机邮政编码的最佳方法