RESTful GET,如果存在大量参数,是否有必要变通一下?
---更新 20160213 ---
突然发现貌似 Polyfill 的方案好像和
@立青童鞋的想法类似。。
---更新 20160213 ---
正如
@张立理@刘尚奇所说,确实查询条件过长的情况有可能存在,但是倾向于认为其设计的 API 过于复杂(对于每一种 Entity 的接口,都要另外设计一个 Query<Entity> 的接口),并且导致了有条件查询和无条件查询接口的不一致性,以及使用了一个没有确切 Representation 的中间类型。所以在此重新给出一个简洁一致的通用接口。
1. 无条件查询:
直接 GET。
GET /goods HTTP/1.1
2. 简单条件查询:
查询条件直接作为 Query 带入 URL 中。
GET /goods?name=microsoft&description=da.fa.hao HTTP/1.1
3. 复杂条件查询(两步):
先将查询条件创建为一个资源,然后将资源 ID 作为 URI 的 Query 部分。
POST /queries HTTP/1.1
Content-Type: text/x-www-form-urlencoded
*(header CRLF)
name=microsoft&create_time=2000-01-01T00:00:00&description=da.fa.hao&status=whatever&owner=whoever
// or
POST /queries HTTP/1.1
Content-Type: application/json
*(header CRLF)
{
"name": "microsoft",
"create_time": "2000-01-01T00:00:00",
"description": "da.fa.hao",
"status": "whatever",
"owner": "whoever"
}
GET /goods?query_id=1234567 HTTP/1.1
简单地说就是对复杂条件做了一个 Polyfill。
大概的过程:
function getURIParams(queryObject) {
let queryString = $.param(queryObject);
if(prefix.length + queryString.length + 16 <= 8000) {
return Promise.resolve(queryObject);
} else {
return $.post('/queries', queryObject) // or $.post('/queries', queryString)
.then(raw => ({query_id: JSON.parse(raw).id}))
}
}
const prefix = '/goods';
let queryObject = getQuerySomehow();
getURIparams(queryObject).then(params => {
return $.get(prefix, params);
}
--- 原答案 ---
首先贴一下引用:
Various ad hoc limitations on request-line length are found in practice. It is RECOMMENDED that all HTTP senders and recipients support, at a minimum, request-line lengths of 8000 octets.
From RFC7320 Section3.1.1(Request Line):
RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and RoutingSHOULD This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.
From RFC2119:
RFC 2119 - Key words for use in RFCs to Indicate Requirement Levels任何 HTTP 协议客户端和服务器都应当支持 8000 字节的首行(方法名 + URI + HTTP 版本号),可以理解成支持 7980+ 字节的 URI。浏览器作为一个通用的 HTTP 客户端实现,当然是应当满足规范中的所有 SHOULD 部分。
所以不要说什么 HTTP 协议没有规定 URI 长度,当然要兼容特定的历史版本是另一回事。
---
所以,大量能有多大?HTTP 标准的要求(准确的说是建议)为 8000 字节,实现中即便低版本 IIS 都能支持 2048 字节的 URL,看不出除了嵌入 Base64 编码的文件外要如何达到。
Query string 都是你传对象自动转换出来的,又不是说放 URL 里就要你手动花式拼接字符串什么的。
而且放 URL 还是放正文里只是 Query string 出现在首行末尾还是末行末尾的区别,string 还是那个 string,传输内容上并没有什么本质区别。
对于服务器端都是自动解析成字典 or 对象也依然没有什么区别。
按 HTTP 语义来说,正文部分应该是实体内容,而查询条件作为实体的辅助定位条件不论是用 GET 还是 POST 都应该放在 URL 里,这也正是【统一资源定位符】的含义。
无副作用、幂等的从服务器端获取内容,自然应该是 GET,也方便缓存等操作。
综上所述,所以很好奇为什么 URL 里不能有大量参数(仅仅是查询参数的话),何来需不需要变通?