我需要设计一个RESTful查询API,该API根据一些过滤器返回一组对象。通常的HTTP方法是GET。唯一的问题是,它至少可以有十二个过滤器,并且如果我们将所有过滤器都作为查询参数传递,则URL可能会很长(足够长以被某些防火墙阻止)。
减少参数数量不是一种选择。
我可以想到的一种替代方法是在URI上使用POST方法,并将过滤器作为POST正文的一部分发送。这是否反对RESTfull(进行POST调用以查询数据)。
有人有更好的设计建议吗?
我需要设计一个RESTful查询API,该API根据一些过滤器返回一组对象。通常的HTTP方法是GET。唯一的问题是,它至少可以有十二个过滤器,并且如果我们将所有过滤器都作为查询参数传递,则URL可能会很长(足够长以被某些防火墙阻止)。
减少参数数量不是一种选择。
我可以想到的一种替代方法是在URI上使用POST方法,并将过滤器作为POST正文的一部分发送。这是否反对RESTfull(进行POST调用以查询数据)。
有人有更好的设计建议吗?
Answers:
请记住,使用REST API,这全都是您的观点问题。
REST API中的两个关键概念是端点和资源(实体)。松散地说,端点要么通过GET返回资源,要么通过POST和PUT接受资源,依此类推(或上述方式的组合)。
接受POST后,您发送的数据可能会导致也可能不会导致创建新资源及其关联的端点,这很可能不会在POSTed网址下“生效”。换句话说,当您POST时,您会将数据发送到某个地方进行处理。POST端点通常不在资源所在的位置。
引用RFC 2616(省略了不相关的部分,并突出显示了相关的部分):
9.5开机自检
POST方法用于请求源服务器接受请求中包含的实体作为请求行中Request-URI标识的资源的新下属。POST旨在允许采用统一的方法来覆盖以下功能:
- ...
- 向数据处理过程提供数据块,例如提交表单的结果;
- ...
...
POST方法执行的操作可能不会导致可以由URI标识的资源。在这种情况下,取决于响应是否包括描述结果的实体, 200(确定)或204(无内容)是适当的响应状态。
如果在原始服务器上创建了资源,则响应应为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": "..."
}
没有任何关于此端点的RESTful。它接受请求主体形式的数据(实体)。这些数据就是搜索条件 -像其他任何DTO一样。该端点响应以下请求生成资源(实体):Search Results。搜索结果资源是一种临时资源,可立即提供给客户端,无需重定向,也不会暴露于其他规范的URL。
它仍然是REST,只是实体不是书籍-请求实体是书籍搜索条件,响应实体是书籍搜索结果。
BooksSearchCriteriaDTO
和BooksSearchResultsDTO
。
POST
于CRUD的C部分。我会使用普通的200,也可以选择204作为空的搜索结果。
许多人已经接受了这样的做法,即具有太长或太复杂的查询字符串(例如,查询字符串不能轻松处理嵌套数据)的GET可以作为POST发送,而主体中表示的是复杂/长数据的请求。
在HTTP规范中查找POST规范。它的范围非常广。(如果要在REST漏洞中驾驶战舰,请使用POST。)
您将失去GET语义的某些优势...像自动重试一样,因为GET是幂等的,但是如果您能忍受这一点,那么接受使用POST处理真正较长或复杂的查询可能会更容易。
(大胆的题外话...我最近发现,根据HTTP规范,GET 可以包含一个文档正文。有一个部分写着:“任何请求都可以有一个文档正文,但本节中列出的除外”。我搜索并找到了一个HTTP作者正在谈论的线程,这是有意为之的,因此路由器等无需区分不同的消息。练习很多基础结构部件确实会降低GET的主体。因此,您可以使用主体中表示的过滤器进行GET,例如POST,但您会掷骰子。)
简而言之:进行POST,但使用X-HTTP-Method-Override标头覆盖HTTP方法。
实际要求
POST /书籍
实体主体
{“ title”:“ Ipsum”,“ year”:2017}
标头
X-HTTP-Method-Override:GET
在服务器端,检查标头X-HTTP-Method-Override是否存在,然后将其值用作在后端建立到最终端点的路由的方法。另外,将实体主体作为查询字符串。从后端的角度来看,该请求只是一个简单的GET。
这样,您可以使设计与REST原理保持一致。
编辑:我知道此解决方案最初旨在解决某些浏览器和服务器中的PATCH动词问题,但在URL非常长的情况下,它也适用于GET动词,这是问题中描述的问题。
X-
删除和1.5。它不会覆盖现有规格。…… X-
IMO会留在这里吗?
如果您使用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。