Hacker News 中文摘要

RSS订阅

详解新的HTTP QUERY方法 -- The new HTTP QUERY method explained

文章摘要

HTTP新定义了QUERY方法,用于解决传统GET请求在复杂查询场景下的局限性,如URL长度限制和安全性问题,为API提供更规范的查询方式。

文章总结

新HTTP QUERY方法解析

在RESTful API领域,我们长期遵循一套严格的规则:GET用于获取数据,POST用于创建实体,PUT用于更新资源。HTTP方法向服务器传达操作意图。近期发布的RFC 10008定义了新的HTTP QUERY方法。既然已有其他方法,为何还需要它?

从技术角度看,HTTP方法只是字符串。理论上,你可以用FETCH /api/v1/users替代GET /api/v1/users。但实践中,GET和POST等标准方法有大量RFC和隐含行为规范。例如,浏览器输入地址或点击书签时发送GET请求,标准HTTP表单仅支持GET和POST,多数代理、防火墙和服务器也只允许标准方法。

使用GET进行查询的局限

传统上,通过GET请求的查询参数过滤资源(如/api/v1/users?role=admin&status=active&sort=desc)适用于简单场景。但复杂关系查询、深层嵌套或高级逻辑会导致URL冗长难读,甚至超出浏览器或服务器字符限制。其他问题包括:非ASCII字符需编码增加请求大小;服务器和中间件可能记录参数引发隐私问题;数组等数据结构的表达方式不统一(如?roles[0]=admin?roles=admin的差异);深层嵌套结构同样缺乏标准。

既然查询参数有缺陷,为何不直接用GET请求发送JSON请求体?理论上可行,但HTTP RFC虽未明确禁止GET携带请求体,却指出不应这样做。实际中,不同客户端、代理和服务器对GET请求体的处理各异:有的直接拒绝,有的丢弃请求体,有的则正常解析。因此,使用GET带请求体是糟糕的做法,可能导致企业防火墙后的用户或不同浏览器无法正常访问。这也是没有新RFC规定GET应支持请求体的原因——会破坏大量现有实现。

使用POST的变通方案

由于GET发送请求体可能引发问题,变通方案是使用POST。POST允许请求体,但存在语义问题:POST被定义为非幂等,用于创建资源或处理操作。这在实际中会带来麻烦,例如实现失败自动重试时。GET方法被定义为安全且幂等,只要服务器实现正确,重试失败请求无需担心副作用。而POST无法让代理或中间件自动识别操作为只读,例如中间件可能自动缓存GET请求,但对POST无效。

QUERY方法

经过多年讨论,QUERY方法应运而生。RFC大致规定:QUERY类似于GET,但带有请求体,被设计为安全且幂等。QUERY请求可被缓存,但实现时必须将请求内容纳入缓存键。总之,它终于为复杂搜索查询提供了合适的HTTP方法。

QUERY的注意事项

在将所有搜索端点切换为QUERY前,需考虑以下几点:

  • 对HTTP QUERY的支持目前仍非常有限,可能持续一段时间。完全普及可能需要数年。例如,Kreya在1.20版本中才原生支持QUERY(此前已支持自定义方法),其他客户端、代理和服务器可能仍会拒绝。
  • 标准GET查询(数据在URL参数中)仍然完全适用。若无迫切需求,无需更改。
  • 若用户需要分享或收藏过滤数据的链接,请继续使用GET请求,因为QUERY请求无法实现链接分享。
  • 为QUERY请求实现自定义缓存比GET更困难,因为需考虑请求体。

结论

简而言之,HTTP QUERY替代了只读请求中的POST。尽管全面支持尚需时日,但当标准GET请求无法满足需求时,你仍应考虑(并测试!)使用QUERY。

评论总结

根据评论内容,总结如下:

支持HTTP QUERY的观点: - 解决GET请求不能带请求体的问题,避免使用GET带请求体的“hack”方式(评论10:"You're not supposed to use GET with a Body, this is a hack, therefore having an explicit method makes sense") - 开发者长期期待类似功能(评论3:"I've had my fair share of situations where I wished for something like HTTP QUERY") - 允许DELETE请求带请求体也有类似需求(评论5:"It would be nice to allow bodies on DELETE as well"

反对或质疑HTTP QUERY的观点: - 认为直接允许GET带请求体更简单(评论8:"We should have just added optional body support for GET requests. So much simpler...") - 担心新方法破坏现有REST/CRUD模式(评论13:"This breaks rest/crud") - 质疑缓存可行性:HTTPS加密后CDN无法缓存(评论12:"Query body is encrypted by https. So CDN will not be able to cache results") - 认为新方法可能被滥用,如阻止分享链接(评论11:"What are the chances sites start using this to prevent sharing links...") - 指出企业防火墙和旧浏览器可能不支持(评论4:"using QUERY requests for quite some time from now"

中立或技术性讨论: - 与GraphQL兼容性存疑(评论15:"Will this be compatible with graphql?") - 认为应优先修复现有问题而非添加新方法(评论14:"Don't add new stuff (query). Instead fix the broken shit that's already added (get)") - 指出CoAP已有类似功能,但HTTP代理存在摩擦(评论7:"CoAP already has it (which creates friction in building CoAP<->HTTP proxies)"