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,如果存在大量参数,是否有必要变通一下? 的相关文章

  • 使用矩阵参数创建 GET 请求

    我将使用的网络服务需要矩阵参数 http tester com v1 customers lastname Jackson firstname Tim bookingreference 7Y9UIY 而不是通常的 http tester c
  • 使用 HTML 表单时如何在 HTTP 请求正文中发送数据?

    HTTP 规范规定 POST 请求可以包含任意数据体 An HTML form元素可以 POST 到 URL 并且可能包含input元素 但那些input元素变成查询字符串 我怎样才能得到一个form还可以在按下提交按钮时发送的 HTTP
  • 为什么 HttpClient 使套接字保持打开状态?

    在创建 使用和处置多个 HttpClient 时 我注意到有套接字处于 TIME WAIT 状态 例如 运行以下命令后 using System Net Http namespace HttpClientTest public class
  • 从开放的 HTTP 流中读取数据

    我正在尝试使用 NET WebRequest WebResponse 类来访问 Twitter 流 API 此处 http stream twitter com spritzer json 我需要能够打开连接并从打开的连接中增量读取数据 目
  • ReverseProxy取决于golang中的request.Body

    我想构建一个 http 反向代理 它检查 HTTP 主体 然后将 HTTP 请求发送到它的上游服务器 你怎么能在 Go 中做到这一点 初始尝试 如下 失败 因为 ReverseProxy 复制传入请求 修改它并发送 但正文已被读取 func
  • Spring webflow 应用程序:HTTP 302 暂时移动

    我的 java 应用程序中的每个请求都会生成另外 2 个带有 HTTP 302 错误的请求 例如 如果请求查看名为板 html 这个请求是从首页 html 我收到按以下顺序生成的 3 个请求 POST home html 302 Moved
  • 使用 Google OAuth2.0 时出现错误请求

    从 Salesforce 中使用 Google OAuth 时 我收到 400 错误请求 以下错误与无效的 grant type 有关 但如果您查看 使用刷新令牌 下的文档 您会发现它是正确的 https developers google
  • asp.net core http 如果没有内容类型标头,则删除 `FromBody` 忽略

    我在 http 中使用 bodyDELETE要求 我知道目前删除主体是非标准的 但是允许的 使用时出现问题HttpClient它不允许删除请求的正文 我知道我可以使用SendAsync 但我宁愿让我的 API 更加灵活 我希望这个机构是可选
  • 通过 HTTPS 加载页面但请求不安全的 XMLHttpRequest 端点

    我有一个页面 上面有一些 D3 javascript 该页面位于 HTTPS 网站内 但证书是自签名的 当我加载页面时 我的 D3 可视化效果不显示 并且出现错误 混合内容 页面位于 https integration jsite com
  • 按照约定应返回哪些 REST PUT/POST/DELETE 调用?

    根据 REST 意识形态 PUT POST DELETE 请求的响应正文中应该包含什么 返回码呢 是HTTP OK enough 如果有的话 这种约定的原因是什么 我发现了一篇描述 POST PUT 差异的好文章 发布与放置 http ww
  • 使用特定 HTTP 方法链接到页面 (DELETE)

    如何像 Rails 那样链接到页面并让浏览器使用 DELETE 方法调用它 我试过 a href DELETE ME a 但不起作用 我使用 Node js 所以我可以用它来处理 DELETE 方法 你不能 链接只会触发 GET 请求 您可
  • 在 iOS 中,http 204 响应返回空白页面,有办法阻止这种情况吗?

    以前可能有人问过这个问题 但我似乎找不到解决方案 所以如果是这种情况 我深表歉意 我正在开发一个使用express的简单节点应用程序 其中一个帖子路由返回 http 204 并发送它 下面是我的代码 router post id funct
  • HttpWebRequest vs Webclient(特殊场景)

    我知道这个问题之前已经回答过thread https stackoverflow com questions 1694388 webclient vs httpwebrequest httpwebresponse 但我似乎找不到详细信息 在
  • Android - API 请求

    我开发了一个应用程序 它也在 iPhone 上 问题出在 api 请求上 我为所有请求设置了超时 有时会出现 30 60 秒的中断 看起来这个应用程序执行了几个请求 然后就中断了 一直超时 大约 45 秒后一切正常 不知道是服务器问题还是安
  • iOS WKWebView 处理文件下载

    我面临以下问题 在 Web 界面中 文件下载是通过锚标记触发的 如下所示 a href bla blabla a 虽然 Safari 浏览器可以处理此请求并打开一个对话框来处理文件 但 WKWebView 将此视为普通链接并且不对其执行任何
  • 如何使用 python 的 http.client 准确读取一个响应块?

    Using http client在 Python 3 3 或任何其他内置 python HTTP 客户端库 中 如何一次读取一个分块 HTTP 响应一个 HTTP 块 我正在扩展现有的测试装置 使用 python 编写 http clie
  • WCF WebHttp 混合身份验证(基本和匿名)

    所有这些都与 WebHttp 绑定有关 托管在自定义服务主机中 IIS 目前不是一个选项 我已经实现了自定义 UserNamePasswordValidator 和自定义 IAuthorizationPolicy 当我将端点的绑定配置为使用
  • 使用 Unity 在 C# 中发送 http 请求

    如何使用 Unity 在 C 中发送 HTTP GET 和 POST 请求 我想要的是 在post请求中发送json数据 我使用Unity序列化器 所以不需要 新的 我只想在发布数据中传递一个字符串并且能够 将 ContentType 设置
  • 从手机访问本地主机[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在使用
  • 使用 WCF 支持“application/x-www-form-urlencoded”发布数据的最佳方式?

    我正在基于 W3C 规范构建 WCF 服务 该规范定义了接受 application x www form urlencoded 发布数据的 RESTful Web 服务端点 默认情况下 WCF 不支持这种类型的消息编码 我发现了许多创建如

随机推荐

  • 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 就会设