我需要设计一个 RESTful 查询 API,它基于一些过滤器返回一组对象。通常的 HTTP 方法是 GET。唯一的问题是,它可能至少有12个过滤器,如果我们将所有过滤器作为查询参数传递,URL 可能会变得很长(长到足以被某些防火墙阻塞)。
不能减少参数的数量。
我能想到的一种替代方法是利用 URI 上的 POST 方法,并将过滤器作为 POST 主体的一部分发送。这与 RESTfull (对查询数据进行 POST 调用)相反吗。
有人有更好的设计建议吗?
很多人已经接受了这样的做法: 一个查询字符串太长或太复杂的 GET (例如,查询字符串不容易处理嵌套数据)可以作为 POST 发送,复杂/长的数据表示在请求的主体中。
在 HTTP 规范中查找 POST 的规范。范围非常广。(如果你想让一艘战舰通过 REST 中的一个漏洞... 使用 POST。)
你失去了 GET 语义的一些好处... ... 比如自动重试,因为 GET 是等幂的,但是如果你能忍受这一点,那么接受使用 POST 处理非常长或者非常复杂的查询可能会更容易。
(lol long 偏题... 我最近发现,根据 HTTP 规范,GET 可以包含一个文档主体。有一个部分解释说,“任何请求都可以有一个文档主体,除了这个部分中列出的那些”... ... 而它引用的部分没有列出任何。我搜索并找到了一个线程,在这个线程中 HTTP 的作者谈到了这个问题,这是有意为之的,这样路由器之类的就不必区分不同的消息了。但是,在实践中,许多基础结构片段确实丢弃了 GET 的主体。因此,您可以使用主体中表示的过滤器(如 POST)来获取,但这是在孤注一掷。)
请记住,使用 RESTAPI,一切都取决于您的观点。
REST API 中的两个关键概念是端点和资源(实体)。简单地说,端点通过 GET 返回资源,或者通过 POST 和 PUT 等方式(或者上述方式的组合)接受资源。
通过 POST,您发送的数据可能会或可能不会导致创建一个新的资源及其相关的端点,这些端点很可能不会在 POST URL 下“活动”。换句话说,当您 POST 时,您将数据发送到某个地方进行处理。POST 端点不在通常可以找到资源的位置。
引自 RFC 2616(省略不相关部分,突出相关部分) :
9.5 POST POST 方法用于请求原始服务器接受 作为资源的一个新的从属实体包含在请求中 由 Request-Line 中的 Request-URI 标识 允许采用统一的方法来涵盖以下职能: ... 向数据处理过程提供数据块,例如提交表单的结果; ... ... POST 方法 可能不会导致可以通过 URI 标识的资源执行的操作。在这种情况下,200(OK)或204(No Content)是适当的响应状态,具体取决于 响应是否包含描述结果的实体。 如果一个资源已经在原始服务器上创建,响应应该是201(创建) ..。
POST 方法用于请求原始服务器接受 作为资源的一个新的从属实体包含在请求中 由 Request-Line 中的 Request-URI 标识 允许采用统一的方法来涵盖以下职能:
...
POST 方法 可能不会导致可以通过 URI 标识的资源执行的操作。在这种情况下,200(OK)或204(No Content)是适当的响应状态,具体取决于 响应是否包含描述结果的实体。
如果一个资源已经在原始服务器上创建,响应应该是201(创建) ..。
我们已经习惯于用端点和资源来表示“事物”或“数据”,无论是用户、消息还是书籍——不管问题领域要求什么。但是,端点也可以公开不同的资源-例如搜索结果。
考虑下面的例子:
GET /books?author=AUTHOR POST /books PUT /books/ID DELETE /books/ID
这是一个典型的 REST CRUD:
POST /books/search { "keywords": "...", "yearRange": {"from": 1945, "to": 2003}, "genre": "..." }
这个端点没有什么是非 REST 的。它接受请求体形式的数据(实体)。这些数据就是 搜寻准则-和其他数据一样的 DTO。此端点响应请求生成一个资源(实体) : 搜寻结果。搜索结果资源是一个临时资源,它可以立即提供给客户端,不需要重定向,也不需要从其他规范 URL 暴露出来。
它仍然是 REST,除了实体不是图书——请求实体是图书搜索标准,响应实体是图书搜索结果。
简而言之: 使用 X-HTTP-Method-Override头部创建一个 POST 但覆盖 HTTP 方法。
真正的请求
邮政/书籍
实体身体
{ “ title”: “ Ipsum” 年份: 2017 }
标题
X-HTTP-Method-Override: GET
在服务器端,检查头 X-HTTP-Method-Override 是否存在,然后将其值作为构建到后端最终端点的路由的方法。另外,将实体主体作为查询字符串。从后端的角度来看,请求变成了一个简单的 GET。
这样可以使设计与 REST 原则保持一致。
编辑: 我知道这个解决方案最初是为了解决一些浏览器和服务器中的 PATCH 谓词问题,但是对于一个非常长的 URL (问题中描述的问题) ,它也适用于我的 GET 谓词。
如果您正在使用 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。