RESTful 有用吗? HTTP 有 GET POST 就足够了?

2017-02-15 12:59:26 +08:00
 noli

不少程序员都是这么认为的,基于 HTTP API 的服务,只要用 GET 请求和 POST 请求就足够了。 像 RESTful 这样的 大量使用 PUT , DELETE 请求是不必要的。

真的吗,我来举一个例子。

假设有一类资源 ResourceXYZ ,对其有增删查改的操作。 如果只使用 GET POST 之类的设计方式,那么很可能会设计以下的请求接口:

POST .../addResourceXYZ
POST .../delResourceXYZ
GET .../getResourceXYZ?resourceId=resourceId
POST .../updateResourceXYZ

如果按照 RESTful 的 设计方式,很可能会设计以下的请求接口

POST .../ResourceXYZs
DELETE .../ResourceXYZ/{resourceId}
GET .../ResourceXYZ/{resourceId}
PUT .../ResourceXYZ/{resourceId}

现在假设,客户端要获取该资源,其 ID 为 resourceId 。 如果成功,那么一切都好说。 如果失败, Restful 的处理方式是,通过 HTTP status 返回错误码来表示原因,例如 404 表示该资源不存在。

那么只用 GET POST 两种方法的方式呢? 响应请求

GET .../getResourceXYZ?resourceId=resourceId

的时候能不能也用 404 呢?

按照 404 的语义,响应 404 是不对的: 因为客户端请求的 URL 实际上是正确的,只是对应的参数没有找到对应的结果 很多时候,就只能靠响应 200 然后返回空数据或者空对象来处理了。 例如 Content-type 为 application/json 时,可以返回 {} 或者

{
    "error": "not found",
    "code": 404
}

这样就会要求客户端,必须处理 HTTP 回复的具体内容,而不能只处理头部。 那么客户端要怎么处理这个 json 呢 要先解析 json ,然后尝试分别这是一个资源的内容,还是一个错误提示。

对于强类型语言例如 C/C++ OC Swift 写的客户端来说,恐怕就忍不住要问候服务端程序员一家了。

更重要的是……

没有库会支持这种拍脑袋式的设计。

全文完,欢迎拍砖。

42315 次点击
所在节点    程序员
207 条回复
noli
2017-02-16 23:57:31 +08:00
@cxe2v

反正 v2 上发了帖就改不了。你愿意指出具体问题你就说,不想认真就别回。

你要说 RESTful 规范不适合的时候强行用,真是好笑了——我做了什么 RESTful 的系统,又是怎么不适合的?
或者我举了哪个例子,让你觉得 RESTful 不合适?
怎么不合适你又不说,不好意思,不是你女朋友你老婆,我不负责体贴你。

既然我举的例子你不服,觉得微信是王道,你说出个微信的道理来,有没有理大家评评嘛。

觉得说不过、不值得提前撤,也是可以的。
接受我的奚落就是了。
danielmiao
2017-02-17 00:30:41 +08:00
@noli
本来我是不想回的,因为这种脱离生产的为辩论而去做辩论,没有特别的意义。但是看到你这么酸的。。。。。

我从主贴上看到您是驳斥这种 Json Envelope ,你希望通过只处理 http 头来解决问题。。。但是后续又提出“ HTTP 错误码是为工作在 HTTP 层的各路非业务设备看的 ”,那我的理解就是关于资源有无,应该是业务层,而非 HTTP 层的。。所以真心不知道你是什么观点。
至于你说的:“ curl -i 就可以看到是哪个服务器发出来的响应了。 ”
我觉得没问题,能解决问题,但是,如果不用这些方法,只是通过日志直接能判断服务的问题,这样的效率不是更高,只是为了遵循某个规范,而搭进去排查运维、开发的人力和时间成本毫无意义。

至于你提的 2 大厂。。。只是代表了一种设计思想(错误码和 json 同时使用),但是并非强制标准抑或其他。


国内几大厂以及主推微服务架构的 Netflix ,则推行的则是 HTTP 状态只负责链路层,业务错误由另外结构体处理。
从 spring-cloud-feign 上来看,目前的方案是:非 200 的错误的处理方案是统一的 errorDecode ,也就是非 200 由处理链路层的方法去统一管理。

所以说不管方案是不是纯血的 Restful ,贴近生产,符合实际,能提高劳动效率的方案才有意义吧。
noli
2017-02-17 01:44:31 +08:00
@danielmiao

我知道你为什么会这么理解我的观点了。

明确一下我的观点:
0. 我反对只用 GET POST
1. 如果只用 GET POST ,那么 GET 一个资源 ID 错了的时候用 404 会有歧义
2. 如果不希望客户端错误理解 404 (并且将错就错),那么返回 200 和 一个 JSON 应该是可行的做法
3. 可是这样就必须强迫客户端总是要解析 JSON ,并且如果真的是资源不存在的时候, HTTP 设备也无法知晓

所以 3 就只用 GET POST 这种方式带来的隐忧,也因为如此我反对这种设计。
halden
2017-02-17 01:48:47 +08:00
做前端的,表示 RESTful 这个东西应该是为了前端方便而来的。你可以说它是风格,但我觉得 RESTful 作为不是硬性的“标准”可能更加适合,因为我肯定希望后端全部按照这套东西来写 api ,这样前端可以用 js 根据不同的 code 做相应的反馈,状态码都是固定现成的,一套 js 只需要稍作修改就可以用在其他地方

create(post) - return 201 / 409
delete(delete) - return 200 / 404
edit(patch) - return 200 / 204 /404
read(get) - return 200 / 404
replace(put) - return 200 / 204 / 409

这一套可以应付大多数情况了,而且 201/204/409 的使用显然比单纯用 200/404 来得人性化

我看楼上有人举『移动到文件夹 X 』的例子,很明显这个已经超出了 RESTful 所定义的范畴,你强上 RESTful 肯定不合适,但比如你 增删改查 设计成符合 RESTful 的架构,然后其他的再自定义这完全 OK 啊
lightening
2017-02-17 06:22:22 +08:00
@magict4 非常建议有空的时候真的看一下。 dhh 作为 Ruby on Rails 的设计者,很多思想都非常富有远见。而且他不像很多大牛一样是极端。他先介绍了 REST 风格到底给你带来了什么好处,也说了在什么情况下需要 make exception 。
cxe2v
2017-02-17 09:06:58 +08:00
@noli 第一啊,我并没有说你做的什么系统有什么问题,只是你自己前后矛盾而已
第二,可能你语文不太好,不能体会字面背后地意思,那我现在说清楚,不要为了 RESTful 而 RESTful ,要看实际情况来
第三,微信的例子,就用我最近要用到的微信公众号接口来说吧,它也并没有采用 RESTful 风格,而是定义了一个确定的 JSON 结构,然而我感觉在你心目中微信根本不算什么,在你眼中,要每天百万级的接口调用才叫牛逼

还是那句话,你开心就好,我真是闲得蛋疼

juice
2017-02-17 09:28:57 +08:00
看看 fb 的 Graphql ,也是不错的一个解决方案
noli
2017-02-17 09:52:48 +08:00
@cxe2v

1. 前后什么内容什么观点矛盾了请指出。要不你看看 #123 是不是你自己误读了。说话说一半神惹人烦

2. 什么实际情况请说明,别装 B ,说话说一半神惹人烦。

3. 微信的接口确实没啥牛逼的。各家 sns 的 api 封装是我曾经做过的产品之一,各位写移动 app 调用的 sdk 可能有可能包含我的代码。所以我觉得我起码有调查过,你说它牛逼就因为它是微信?
wizardforcel
2017-02-17 10:06:55 +08:00
@noli

> 你一直在说 http api 调度代价大,事实上数据库访问的代价更大,连接数基本上都是有上限限制的。数据库的调用逻辑更是测了又测。我扩张几台几十台 http server 简直是简单得不要不要的。

就算真的要用集群,就必须用 REST ??呵呵。你们家 REST 还是跟集群绑定的??

REST 的发明者都没你这么强硬吧??你是来布道的,但是大家的选择权也是很重要的。 REST 虽然优雅,但是我不喜欢就可以不用。
wizardforcel
2017-02-17 10:29:36 +08:00
终于扯到返回信息的处理了。。

[按照 404 的语义,响应 404 是不对的: 因为客户端请求的 URL 实际上是正确的,只是对应的参数没有找到对应的结果 很多时候,就只能靠响应 200 然后返回空数据或者空对象来处理了。 ]

你前面也说了,自定义错误码就能解决。(但是国内多数厂商提供的 API 是 200 + errmsg 这种方式,没你想象的这么简单)。

[这样就会要求客户端,必须处理 HTTP 回复的具体内容,而不能只处理头部。]

就算拿 HTTP 状态区分,对于成功的请求,还是要解析 JSON 的。反正 JSON 这块你绕不过去。

[对于强类型语言例如 C/C++ OC Swift 写的客户端来说,恐怕就忍不住要问候服务端程序员一家了。]

JSON 库的封装跟强不强类型没关系,跟是否存在反射有关系。 OC/Swift 的 Runtime 十分强大,所以把 JSON 变成对象是没问题的。

至于 C/C++ 嘛,在互联网的服务端 /客户端中占得比重太少了,我设计个接口为啥要考虑它??那我是不是还要考虑一下 Delphi 、 COBOL ??
noli
2017-02-17 10:33:07 +08:00
@wizardforcel

谁强迫你了?谁布道了?
我在批评乱改 RESTful 规范然后又搞出自以为高明的设计。

选择权很重要?
我们不聊政治,按需遵守规范就是降低效率浪费人力浪费金钱,我觉得这些比什么鸟什子选择权重要得多。
wizardforcel
2017-02-17 10:36:14 +08:00
@noli

你忽略了我上面那句话。

mysql-cluster 是跟 REST 绑定的?? redis-cluster 是跟 REST 绑定的??

谁告诉你用集群就必须用 REST 了??数据库连接背后就不能是集群??
noli
2017-02-17 10:42:07 +08:00
@wizardforcel

我说了很多次,也贴了 Google Amazon 的做法,我不介意再重新说明一次我的观点:
*** 自定义错误码是不够的,必须结合 HTTP STATUS ***

而我帖子里面举的例子, GET POST 返回 200 然后 json 说有错这种做法,就是违背 HTTP 语义乱来的做法。
情形就好像 TCP 里面明明发了 ACK 却想要对方重新发送一样鬼扯。

“至于 C/C++ 嘛,在互联网的服务端 /客户端中占得比重太少了”
当我说客户端的时候,你想到的是手机、浏览器;
而我想到的还有 Proxy SERVER , CDN Server
你只关心业务,我关心的是整个网络上的机器。
所以视野不同,结论不同。
如果算上我说的,你还会认为“ C/C++ 在互联网的服务端 /客户端中占得比重太少”吗?
noli
2017-02-17 10:48:29 +08:00
@wizardforcel

0. 数据库机器比 HTTP SERVER 价格贵得多。

1. 当我增加面向客户的机器时,如果这些机器是纯粹的 HTTP SERVER ,那我就不需要考虑调整数据库集群,但同时带来更好的处理 客户请求的响应性能。

2. 如果这些 HTTP SERVER 我能确保它们实现业务的时候,正确理解和使用 HTTP STATUS 语义,例如 GET 是幂等的, 200 就肯定是成功,这样的语义,那我就能确信它们能降发挥 CDN 的作用降低数据库压力。

3. 遵守 RESTful 的规范确保 这些 HTTP SERVER 能够满足 2.

所以没错,事实就是这么直接,信不信由你,现行的标准里面 RESTful 在集群上就是这么有效果。
Balthild
2017-02-17 14:31:32 +08:00
@noli 你找我要「优雅」的标准?哈哈,找错人了,这个词可不是我先说的哦,我只是顺着楼上某个人的思路向下走。
baconrad
2017-02-17 14:32:08 +08:00
```
「如果你有的只是一個鎚子,那麼所有的東西看起來都像一個釘子」

「把一個熟悉的技術或理念強迫的應用於大量的軟體問題上」的概念已經被認為是一種反模式,一種編程時應該避免的實踐
```

https://en.wiktionary.org/wiki/if_all_you_have_is_a_hammer,_everything_looks_like_a_nail
Cbdy
2017-02-17 15:04:41 +08:00
“不少程序员都是这么认为的”,第一句话,谁这么认为?
noli
2017-02-17 15:05:46 +08:00
@Balthild @baconrad

你看,我讨论问题的诚意在这里。
我给出了一个例子,展开了这个例子,然后根据这个例子讲了我的看法。
有人提出不同意见
我反驳。

而你们做了什么呢?
只是在把一些看起来很有道理的话贴出来
说了什么很有道理的话呢?
“ XX 是好的,可是不是什么时候都是好的”
“人是肯定会死的,但是不要急着去死。”

不如我也送你一句话:
解放思想,实事求是

不用谢
noli
2017-02-17 15:07:20 +08:00
@Cbdy 我相信本帖种不少人表达了类似的意思,甚至说, GET 都不是必须的,有 POST 就够了。
gzq527
2017-02-17 15:10:54 +08:00
这是个找喷贴???

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/340607

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX