这条在讲 HTTP QUERY 方法正式进标准了,RFC 10008,今年六月的事。出处是一篇技术博客,原作者把来龙去脉捋了一遍,从 PATCH 之后十六年没有新 HTTP 方法开始讲起。
我一开始没当回事。HTTP 方法这玩意儿,够用就行,谁没事盯着有没有新方法发布。但读到作者那句「QUERY 是 PATCH 之后第一个新标准方法,中间隔了十六年」才确认值得点——十六年,这个数字本身就是个信号,说明这行业对加方法有多克制,也说明 QUERY 能进来是真的有东西。
原文贴一段过来,作者对 QUERY 和 GET 的对比写得很直白:
QUERY 和 GET 一样是安全、幂等的只读操作,但它允许请求体。这意味着你可以往请求里放 SQL、JSONPath、复杂的嵌套过滤条件,没有 URL 长度限制。
这段是我读完觉得最有价值的部分。不是新方法本身多神奇,是它把两个以前互相矛盾的东西并到一起了:只读 + 带请求体。以前想发复杂查询,要么憋在 URL 里拼字符串,要么拿 POST 顶上去但丢了幂等语义。
「丢了幂等」这个代价,原作者没细讲,我补充一句。因为 POST 不幂等,写出来之后点不点、发不发给同事看都得犹豫——怕他们真拿去当模板写。现在有了 QUERY,replay 一次不会有副作用,这比「能带 body」本身值钱。
读第二遍才注意到,QUERY 响应里可以带 Location 头。作者写的是「响应里的 Location 头指向这个请求的一个持久 URI,之后重放那个 URI,会针对当前数据重新执行原始查询」。这个设计有点意思,相当于系统里留了一个会变结果的引用——URI 不变,但查出来的数据是新的。
我顺手跑了一下。手边没有现成支持 QUERY 的框架,HTTPie 我不确定支不支持自定义方法,最后改用 curl 对着一个本地模拟服务发:
curl --request QUERY \
--header "Content-Type: application/json" \
--data '{"filter": {"age": {"$gt": 18}}, "projection": ["name", "email"]}' \
http://localhost:8000/users
结果是连接直接断了,本地服务不认这个方法。又试了一个支持自定义方法的框架,这回请求发出去了,但服务端收到的是合法请求却不知道怎么路由——因为它不在我注册的路由表里。
跑出来能对上原文那句「现在很少有服务器和客户端支持,估计要 2027、2028 年才有更广泛的采用」。没有框架支持的时候,QUERY 就是个陌生方法,虽然你自己知道它安全幂等,但它不会魔法般地工作,基础设施必须先认识它。
评论区有人争,说 QUERY 解决的都是 POST-then-GET 模式已经能解决的问题——你先 POST 建立查询资源,再用 GET 去读结果,一样可缓存,一样能复用。这个观点我读着觉得有点道理,QUERY 的价值可能不是它提供了什么全新的能力,而是把一种已有的模式固化成方法本身了。语义写在方法名里,不用靠约定俗成。
这也是它值得点开的地方。你读完可能不同意「QUERY 必不可少」,但至少会想清楚一个问题:HTTP 里那四个常用方法撑了这么多年,其实一直在用 workaround 过日子,QUERY 是第一个把「只读查询带 body」这件事从 workaround 里提出来、给个正式名字的方法。
不点链接也能带走的一句:下次有人说 HTTP 查询只能用 GET 和 URL 参数,你可以告诉他 QUERY 已经是标准了,哪怕暂时没地方用。
现在支持它的框架还很少。我的夹子里有一个 RFC 的原文书签,还没读完,等哪天有客户端真支持了,我再跑一遍看看 Location 那个重放机制到底怎么落地。目前只能停在这儿。
