因此,我需要设计一个RESTful查询API,它基于一些过滤器返回一组对象 . 通常的HTTP方法是GET . 唯一的问题是,它可以拥有至少十几个过滤器,如果我们将所有这些过滤器作为查询参数传递,则URL可能会变得很长(足够长以被某些防火墙阻止) .
减少参数数量不是一种选择 .
我能想到的另一种选择是在URI上使用POST方法并将过滤器作为POST主体的一部分发送 . 这是不是RESTfull(对查询数据进行POST调用) .
有没有更好的设计建议?
谢谢
请记住,使用REST API,这都是您的观点问题 .
REST API中的两个关键概念是 endpoints 和资源(实体) . 松散地说, endpoints 要么通过GET返回资源,要么通过POST和PUT等接受资源(或者上面的组合) .
可以接受的是,对于POST,您发送的数据可能会也可能不会导致创建新资源及其关联的 endpoints ,这很可能不会在POSTed网址下“生存” . 换句话说,当您发布POST时,您可以将数据发送到某处进行处理 . POST endpoints 不是通常可以找到资源的位置 .
引自RFC 2616(省略了相关部分,突出显示了相关部分):
9.5 POST POST方法用于请求源服务器接受请求中包含的实体,作为请求行中Request-URI标识的资源的新下级 . POST旨在允许统一的方法涵盖以下功能:...提供数据块,例如提交表单的结果,数据处理过程; ...... POST方法执行的操作可能不会产生可由URI标识的资源 . 在这种情况下,200(OK)或204(No Content)是适当的响应状态,具体取决于响应是否包括描述结果的实体 . 如果已在源服务器上创建资源,则响应应为201(已创建)...
我们已经习惯了代表“事物”或“数据”的 endpoints 和资源,无论是用户,消息还是书籍 - 无论问题域是什么 . 但是, endpoints 也可以公开不同的资源 - 例如搜索结果 .
请考虑以下示例:
GET /books?author=AUTHOR POST /books PUT /books/ID DELETE /books/ID
这是典型的REST CRUD . 但是,如果我们添加:
POST /books/search { "keywords": "...", "yearRange": {"from": 1945, "to": 2003}, "genre": "..." }
这个 endpoints 没有任何非RESTful功能 . 它以请求体的形式接受数据(实体) . 该数据是 Search Criteria - 与任何其他DTO一样 . 此 endpoints 生成响应请求的资源(实体): Search Results . 搜索结果资源是临时资源,立即提供给客户端,没有重定向,也没有从其他规范网址中公开 .
它仍然是REST,除了实体不是书籍 - 请求实体是书籍搜索标准,而响应实体是书籍搜索结果 .
很多人已经接受了这样的做法,即查询字符串太长或太复杂的GET(例如查询字符串不能轻易处理嵌套数据)可以作为POST发送,而复杂/长数据表示在正文中请求 .
在HTTP规范中查找POST的规范 . 这是非常广泛的 . (如果你想通过REST中的漏洞驾驶战舰......请使用POST . )
你失去了GET语义的一些好处......就像自动重试一样,因为GET是幂等的,但是如果你能接受它,那么接受使用POST处理真正冗长或复杂的查询可能会更容易 .
(lol long digression ...我最近发现,通过HTTP规范,GET可以包含一个文档正文 . 有's one section that says, paraphrasing, 1665132 ... and the section it refers to doesn' t列出任何 . 我搜索并找到了一个HTTP作者正在讨论的线程,这是故意的,所以路由器等不会骰子滚动 . )
简而言之:使用X-HTTP-Method-Override标头进行POST但覆盖HTTP方法 .
Real request
邮寄/书籍
Entity body
{“title”:“Ipsum”,“年份”:2017}
Headers
X-HTTP-Method-Override:GET
在服务器端,检查是否存在标头X-HTTP-Method-Override,然后将其值作为构建到后端中最终 endpoints 的路由的方法 . 另外,将实体主体作为查询字符串 . 从后端的角度来看,请求变得简单得到 .
这样您就可以使设计与REST原则保持一致 .
Edit: 我知道这个解决方案最初是为了解决某些浏览器和服务器中的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 Pattern: “poc / test?code = 1&code = 2&code = 3
@QueryParam 会自动将查询参数“orderBy = age&orderBy = name”转换为java.util.List .
4 回答
请记住,使用REST API,这都是您的观点问题 .
REST API中的两个关键概念是 endpoints 和资源(实体) . 松散地说, endpoints 要么通过GET返回资源,要么通过POST和PUT等接受资源(或者上面的组合) .
可以接受的是,对于POST,您发送的数据可能会也可能不会导致创建新资源及其关联的 endpoints ,这很可能不会在POSTed网址下“生存” . 换句话说,当您发布POST时,您可以将数据发送到某处进行处理 . POST endpoints 不是通常可以找到资源的位置 .
引自RFC 2616(省略了相关部分,突出显示了相关部分):
我们已经习惯了代表“事物”或“数据”的 endpoints 和资源,无论是用户,消息还是书籍 - 无论问题域是什么 . 但是, endpoints 也可以公开不同的资源 - 例如搜索结果 .
请考虑以下示例:
这是典型的REST CRUD . 但是,如果我们添加:
这个 endpoints 没有任何非RESTful功能 . 它以请求体的形式接受数据(实体) . 该数据是 Search Criteria - 与任何其他DTO一样 . 此 endpoints 生成响应请求的资源(实体): Search Results . 搜索结果资源是临时资源,立即提供给客户端,没有重定向,也没有从其他规范网址中公开 .
它仍然是REST,除了实体不是书籍 - 请求实体是书籍搜索标准,而响应实体是书籍搜索结果 .
很多人已经接受了这样的做法,即查询字符串太长或太复杂的GET(例如查询字符串不能轻易处理嵌套数据)可以作为POST发送,而复杂/长数据表示在正文中请求 .
在HTTP规范中查找POST的规范 . 这是非常广泛的 . (如果你想通过REST中的漏洞驾驶战舰......请使用POST . )
你失去了GET语义的一些好处......就像自动重试一样,因为GET是幂等的,但是如果你能接受它,那么接受使用POST处理真正冗长或复杂的查询可能会更容易 .
(lol long digression ...我最近发现,通过HTTP规范,GET可以包含一个文档正文 . 有's one section that says, paraphrasing, 1665132 ... and the section it refers to doesn' t列出任何 . 我搜索并找到了一个HTTP作者正在讨论的线程,这是故意的,所以路由器等不会骰子滚动 . )
简而言之:使用X-HTTP-Method-Override标头进行POST但覆盖HTTP方法 .
Real request
邮寄/书籍
Entity body
{“title”:“Ipsum”,“年份”:2017}
Headers
X-HTTP-Method-Override:GET
在服务器端,检查是否存在标头X-HTTP-Method-Override,然后将其值作为构建到后端中最终 endpoints 的路由的方法 . 另外,将实体主体作为查询字符串 . 从后端的角度来看,请求变得简单得到 .
这样您就可以使设计与REST原则保持一致 .
Edit: 我知道这个解决方案最初是为了解决某些浏览器和服务器中的PATCH动词问题,但对于我来说,对于我来说,如果是一个非常长的URL,那么问题中描述的问题就是GET动词 .
如果您使用Java和JAX-RS进行开发,我建议您使用@QueryParam和@GET
当我需要查看列表时,我有同样的问题 .
见例子:
URI Pattern: “poc / test?code = 1&code = 2&code = 3
@QueryParam 会自动将查询参数“orderBy = age&orderBy = name”转换为java.util.List .