RESTful-RESTful GET,如果存在大量参数,是否有必要变通一下?

2023-11-19

问题

比如设计一个GET接口,用来获取满足条件的商品
GET shop/1/goods?

参数可能是五花八门的,name,create_time,description, status, owner…

通常这种情况,如果不考虑RESTful,就会设计成POST。

但是现在RESTful风格要求做成GET,如何处理会比较合适?

张立理回答

首先承认超过GET的URL总长度的情况确实可能存在的,一个比较典型的场景就是多选id,鬼知道一个变态能选出多少个来当然一个合理的应用不应该让这种情况出现,毕竟用手勾选到能超过URL的长度限制应该是会抽筋的,我们亲爱的产品组应该为用户着想至于“全选”和“全选后取消几个”这种场景,其一我很怀疑后者的用户场景是否真的存在,其二可以使用全选和反选标记来给予实现,也并不是什么麻烦事儿继续说真的超过了URL长度限制怎么办,第一反应自然是拿POST来玩,但是使用POST除去教条式的语义性和REST规范之外,一个很严重的影响是无法使用HTTP缓存当然这个也不是什么大问题,毕竟99.99%的应用是不会精心设计HTTP缓存的(是的这句话是在喷包括自己在内的很多工程师),所以搜索这种场景从一开始就几乎是没有HTTP缓存支持那如果我还是想要缓存,还是想要遵守REST规范使用GET怎么办呢?这里有一个理论主义的玩法假设我们对商品进行检索,有这样的URL:

/goods/ 商品集合

然后我们再在其下创建一个叫“查询条件”的集合:

/goods/queries 商品查询集合

我们使用POST来创建一个查询条件

POST /goods/queries

{"categories": [很长很长很长], "keyword": "很长很长很长"}

创建了之后自然会返回一个id,所以这个请求的响应大概就能这样:

HTTP/1.1 200 OK
一堆HTTP头

{"id": 1234567}

然后再拿这个id去查询,查询视为对“查询”这个集合的单个实体获取

GET /goods/queries/1234567

响应自然就是查询应该有的结果,也可以把那个POST请求的响应搞成302以减免前端再编码发下一个请求的工作量

这样可以有效利用缓存,而且完全符合REST的规范,但代价挺大:

  • 需要2次HTTP请求
  • 从URL上就看不出查询条件了
  • 前后端都需要改造,后端大概并不高兴

除此之外,后端可以做一些工作,如相同的查询可以直接共享之前的id,以便更好地使用缓存前面 Trotyl Yu 有质疑对查询建立实体是否合理,我这里很明确地说,REST就是这么玩的,一切皆资源,一切皆可以是实体,只不过也不能像 uazw 那样强行把搜索搞成POST说那是资源的创建,资源还是要有集合+对集合的操作组成的,表面文章还是得做一做回头再来说,其实无法很好地处理这种问题,无法很顺理成章地得出一个合理的解决方案,其根本原因是大家的应用都不是在玩REST设计,只是在实现层面上“看着像REST”而已,你不是使用资源进行系统建模,不是以资源的角度来进行设计,自然遇到问题不会从资源的角度去考虑,最后和REST需要的资源第一位的观点冲突,把自己绕死这种伪REST其实很要不得,要么你就把REST丢掉,只留下“URL好看点不错”这样的目标,要么你就玩纯粹基于资源的设计和实现

刘尚奇回答

先说结论,可以,使用POST来处理参数比较长的search请求并没有违反REST。

再说说
@张立理
同学的答案里可以改进的地方。在张同学的理论主义玩法里:

有这样的URL:

/goods/ 商品集合

然后我们再在其下创建一个叫“查询条件”的集合:

/goods/queries 商品查询集合

我们使用POST来创建一个查询条件

POST /goods/queries

{"categories": [很长很长很长], "keyword": "很长很长很长"}

创建了之后自然会返回一个id,所以这个请求的响应大概就能这样:

HTTP/1.1 200 OK
一堆HTTP头

{"id": 1234567}

然后再拿这个id去查询,查询视为对“查询”这个集合的单个实体获取

GET /goods/queries/1234567

响应自然就是查询应该有的结果,也可以把那个POST请求的响应搞成302以减免前端再编码发下一个请求的工作量

首先要强调,status code和URI, http method一样都是REST里uniform interface的一部分,不考虑这些,不考虑怎么follow link,Restful api就只剩下CRUD了。

我们可以把查询结果建模成一个新创建的resource:

POST /goods/queries

返回的response应该是

HTTP/1.1 201 Created
Location: /goods/queries/1234567

客户端顺着Loacation去找被创建的resource才是正确的HATEOAS。在response body里返回{“id”: 1234567}还可以接受,返回302在这种场景下是对redirect语义的误用。

rfc7231:section-4.3.3 If one or more resources has been created on the origin server as a result of successfully processing a POST request, the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created and a representation that describes the status of the request while referring to the new resource(s).

而如果查询结果是已经存在的resource:

POST /goods/queries

返回的response应该是

HTTP/1.1 303 See Other
Location: /goods/queries/1234567

这么做的好处是利用已有的缓存。

rfc7231:section-4.3.3 If the result of processing a POST would be equivalent to a representation of an existing resource, an origin server MAY redirect the user agent to that resource by sending a 303 (See Other) response with the existing resource’s identifier in the Location field. This has the benefits of providing the user agent a resource identifier and transferring the representation via a method more amenable to shared caching, though at the cost of an extra request if the useragent does not already have the representation cached.

以上当然是一种比较麻烦的玩法,然而并不是说不这么玩就不RESTful了。

把POST创建的resource直接在response body里将数据返回,也是非常自然和practical的。

POST /goods/queries

返回的response直接包含结果

HTTP/1.1 200 OK
other headers...

[{name: 'good1',...}, {name: 'good2',...},...]

很多人误解只有GET方法才能“读”,这里我们POST的response是对已创建资源的一个表述。这里创建的资源是一个临时资源,可以不返回id。resource是一种抽象并不必然等于entity,POST并不一定要创建一个持久化的resource。

rfc2616:section-9.5 The action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on whether or not the response includes an entity that describes the result.

resource可以没有GET方法,就像resource可以没有DELETE一样自然。并且POST的相应不是不能cache,只是因为副作用的原因平时很少用。

rfc7231:section-4.3.3
Responses to POST requests are only cacheable when they include explicit freshness information.

在实际工程中(如果你不是做google),大部分情况下对search criteria的复用很低。并且HTTP的cache其实只是在client和proxy的cache,其实帮不了太多忙。更常见降低latency的方式是在查询响应里只返回基本的信息和uri reference,然后通过UI design或lazy fetching等方式沿着uri把剩下的信息拿回来。

青之民回答

在这里插入图片描述

转载

https://www.zhihu.com/question/36706936

作者:刘尚奇
链接:https://www.zhihu.com/question/36706936/answer/86077778
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RESTful-RESTful GET,如果存在大量参数,是否有必要变通一下? 的相关文章

随机推荐

  • Appium抓取app数据

    主流APP数据抓取难点 1 请求参数加密 sign签名 使用sha1加上md5做辅助加密 2 请求body加密 整个请求体使用DES算法做加解密 3 代理检测反爬 抓包设置代理后 直接不再加载数据 4 私有CA证书反爬 由于公有的证书需要付
  • Scala中sorted、sortBy、sortWith区别

    1 sorted方法真正排序的逻辑是调用的java util Arrays sort 源码 def sorted B gt A implicit ord Ordering B Repr val len this length val b n
  • UG NX10.0软件安装教程

    软件下载 名称 UG NX 10 0 语言 简体中文 安装环境 Windows 下载链接 链接 https pan baidu com s 1SkskLU2CYLQznfGWM7O4HQ 提取码 ersv 安装中有问题请咨询管家微信 don
  • Android面试题最新整理,2022年最新版

    每年的9月和10月 是互联网大厂疯狂招人的时期 也是程序员们跳槽的黄金期 不知道你有没有幻想过这样一个场景 大厂的面试官说 恭喜你通过面试 明天来办理入职吧 今天 为大家整理了2022年Android大厂面试真题 刷企业历年真题 助你轻松搞
  • 大话西游手游有双系统服务器吗,大话西游手游有几个版本_大话西游手游官服和混服怎么区分_玩游戏网...

    大话西游 手游时间服点卡是互通的吗 点卡有两种 一种是大话西游手游内部的点卡 这种点数是在游戏里面购买道具或者计时用的 分为绑定点和交易点 这种是不能通用的 比如我在时间服有两个号 一个是绝代佳人区 另外一个是勿忘初心区 绝代佳人的点卡是不
  • 基于Matlab实现图像融合技术(附上多个仿真源码+数据)

    图像融合技术是一种将多幅图像融合为一幅图像的方法 使得这幅融合图像包含原始图像的所有信息 近年来 图像融合技术已经广泛应用于图像分割 变换和裁剪等领域 本文将介绍如何使用Matlab实现图像融合技术 实现步骤 首先 我们需要了解图像融合的基
  • linux下c语言实现tail -f功能---实时读取变化文件中的增量内容

    最近由于项目需要 需要对文件中实时新增的数据进行处理 结合tail f的逻辑 用c语言实现了这一功能 代码如下 cpp view plain copy include
  • jquery获取select值

  • ARM架构学习(二)——流水线

    本期主题 ARM流水线 往期地址 ARMv7架构学习 ARM流水线 1 流水线概念 2 指令的分解步骤 1 流水线概念 硬件资源总是有限的 有一个明显的方法能改善硬件资源的利用率 这就是pipeline 流水线 技术 其实就是在当前指令结束
  • std::nth_element bug引起的crash问题

    1 源码 auto less compare const MirroringGroup mg1 const MirroringGroup mg2 gt bool return mg1 usage lt mg2 usage std nth e
  • 腾讯云服务器配置选择方法

    腾讯云服务器配置如何选择 CPU内存 带宽和系统盘怎么选择合适 个人用户可以选择轻量应用服务器 企业用户可以选择云服务器CVM 2核2G3M带宽轻量服务器95元一年 2核4G5M服务器168元一年 企业用户可以选择标准型S5云服务器 可以一
  • idea 生成类图

    选中类 ctrl alt u或者ctrl alt shift u 生成类图
  • ArcGIS GraphicsLayer层的特殊要求

    如果你要使用GraphicsLayer这个绘图层 那么你需要注意自己的布局的模式不可以使用 layout absolute 如果你使用了这个布局 那么你的GraphicsLayer层可能会无法使用 比如下面的程序就是因为设置了 layout
  • java 最大公约数和最小公倍数

    题目 题目 输入两个正整数m和n 求其最大公约数和最小公倍数 比如 12和20的最大公约数是4 最小公倍数是60 说明 break关键字的使用 代码一 package l2 for 题目 输入两个正整数m和n 求其最大公约数和最小公倍数 比
  • Counter统计列表中元素出现次数

    使用Counter方法 统计元素在列表中出现的次数 from collections import Counter k labels 1 1 0 1 0 0 1 1 2 2 3 2 2 2 2 Counter返回的是字典 key为列表中元素
  • TVM系列---1.开始使用Tensor Expression

    Author Tianqi Chen https docs tvm ai tutorials tensor expr get started html Tensor Expression入门 这是TVM中Tensor表达语言的入门教程 TV
  • Unity动画系统详解5:BlendTree混合树是什么?

    摘要 Animator中有一个功能 用来解决多个动画之间的混合 经常用于移动动画之间的混合 这个功能叫做BlendTree 混合树 洪流学堂 让你快人几步 你好 我是跟着大智学Unity的萌新 我叫小新 这几周一起来复 yu 习 xi 动画
  • cl : 命令行 warning D9002:忽略未知选项“ /NODEFAULTLIB:library ”

    前言 cl 命令行 warning D9002 忽略未知选项 NODEFAULTLIB library 原因 一下引用 連結器工具警告 LNK4098 执行运行时程序库现在包含指示词 以防止混合不同的类型 如果您尝试在相同的程序中使用不同类
  • leetcode刷题(7)二叉树(1)

    哈喽大家好 这是我leetcode刷题的第七篇 这两天我将更新leetcode上关于二叉树方面的题目 如果大家对这方面感兴趣的话 欢迎大家持续关注 谢谢大家 那么我们就进入今天的主题 文章目录 1 二叉树的前序遍历 题目要求 示例 做题思路
  • RESTful-RESTful GET,如果存在大量参数,是否有必要变通一下?

    问题 比如设计一个GET接口 用来获取满足条件的商品 GET shop 1 goods 参数可能是五花八门的 name create time description status owner 通常这种情况 如果不考虑RESTful 就会设