为什么后端开发都喜欢自己定义 responseCode? HTTP 状态码不够用吗?

2020-05-29 14:10:45 +08:00
 watanuki

所有请求都返回 200,然后自己定义 responseCode, 好像很多大厂的后端接口都是在这样做的,这样做有什么好处? 现在后端开发是不是已经有了关于 responseCode 的统一标准?还是一个公司一套标准? 如果没有统一标准,大家在开发个人的后端项目时也会用 responseCode 吗?

27936 次点击
所在节点    程序员
216 条回复
no1xsyzy
2020-05-30 19:52:52 +08:00
@lscho #176 呃,我已经说清楚了,你在尝试做一个奇美拉,或者说缝合怪,此处作为类比用没有明显区别。缝合怪通常是个设计失误。我提供的不仅仅是 “实现” 上的准则,也是 “用户体验设计” 的准则,除非你有很好的理由,不然提出不能在我所说的框架下直观地实现的本身即是设计失误。
而奇美拉有奇美拉的做法,**如果不能确定用户名可用,你连注册请求都不应该发送**。
no1xsyzy
2020-05-30 20:04:20 +08:00
@lscho #176 举个现实世界的确应当设计为奇美拉的东西吧,Shell,以我电脑上这个 Bash 为例,你输入 ls -a,结果是调用了 ["/bin/ls", "--color=auto", "-a"],注意这里,如果 bash 不能确定 ls 是什么,根本不应该调用任何程序。在调用前 bash 必须先确定 ls 是什么。至少 ls 在 /bin 里,python 在 /usr/bin 里, ,mount_onedrive 在 ~/.bin 里,这得分清楚。
同理,如果用户名存在,这个请求从开头就不应该发出,后端收到时简单失败即可。
no1xsyzy
2020-05-30 20:07:04 +08:00
@cz5424 #178 全站 HTTPS 就是为了避免这个的……
lscho
2020-05-30 20:45:37 +08:00
@no1xsyzy 我已经确定了,是你没看懂。。已经说的很明白了,是在注册的时候,去检测用户名是否存在。不去后端检测,如何能确定用户名是否已存在呢?检测用户名是否存在这个请求不应该发?
lscho
2020-05-30 20:53:34 +08:00
@no1xsyzy 那我再详细描述一下,在可以自定义用户名的注册场景下,用户输入用户名,需要检测用户名是否存在,如果存在,则根据用户常用登录地提供两种逻辑,在常用地,提示找回密码或者直接登录。不在常用地,推荐一组可用用户名。请问如何用 http 状态码表示用户名已存在。

如果你觉得实现不了就是设计失误,那我只能说这是常见场景。
yuekcc
2020-05-30 21:01:39 +08:00
本人前端

我所在的项目,开始的时候,接口是 restful 口味。正常时 http codo = 200,body 中直接就是数据( json ),非 200,body 返回 {errorCode: 123, message: "xxx"} 这样的结构。

后来换人,新加的接口变成了响应码风格,正常异常都是 200 。

一问后台,只回了一句:搞不懂原来为什么这么设计。

我只想说,口味一样就可以了。restful 、响应码我都不介意。只要统一,一样地处理。问题是后台可否保持一致的风格。
ChanKc
2020-05-30 21:09:32 +08:00
如果问题仅仅在于“我如何定义我的错误并准确地告知用户”,我认真介绍一下 RFC7807 所定义的一种媒体格式:application/problem+json
https://tools.ietf.org/html/rfc7807

{
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
'status": 403,
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345",
"/account/67890"]
}

其中 type, title, detail, status 和 instance 都是这个规范定义的成员字段,但也都是可选的,此外别的字段都是可以随意拓展的。

其中 status 的存在就可以有效避免楼里说的 HTTP status 被篡改的问题。

type 要求是一个指向人类可读的错误文档的 URI,如果可以确保这个 URI 不变,调用方可以对这个 URI 进行判断来确定错误。title 和 detail 则是提供了人类可读的说明。

这个格式已经有很多语言的实现,Github 上一搜都能出来很多。而且这个格式是 RESTful 的,因为用到了超媒体。

如果传输过程中 HTTP Body 也不幸被修改了,可能会出现的情况是 HTTP Header 的 Content-Type 也被修改,不是 application/problem+json,那么可以确定问题发生在传输过程中。如果 Content-Type 是 application/problem+json 而 body 无法按照这个格式解析,也很容易确定问题发生在传输过程中。

不懂超媒体的就不要再黑 RESTful 了。
no1xsyzy
2020-05-30 22:01:52 +08:00
@lscho #184 先发请求确定用户名是否存在,再进行注册,很直白吧?
我说了,这本来就是种奇美拉,或者说畸形的设计,我真的不太想跟你讨论这个,污了你我的理智。
我说得这么清楚,你硬要说我没讲,您是真瞎还是装瞎?
no1xsyzy
2020-05-30 22:03:02 +08:00
@lscho #185 我求您了,看过别人说什么再说话,或者不要跟我说话,自己跑墙角跟空气说去,ok ?
no1xsyzy
2020-05-30 22:10:31 +08:00
@lscho #185 而且,
实现不了就是设计失误 ✘
只要实现上稍微有点困难就是设计失误 ✔

仅以您浅薄的见识来断定常见场景是不是有点自大了?
你难道没有发现这种情况下任何人可以通过你放出的界面来知晓任何一名用户的常用地?
难道明显违法就是所谓常见场景?
vizee
2020-05-30 22:23:26 +08:00
你的业务不是 http,不够用不是很正常的吗?说的前端真会处理 code 似的?
lscho
2020-05-30 22:34:35 +08:00
@no1xsyzy 问的意思就是“先发请求确定用户名是否存在,再进行注册”,这个请求你用什么状态码来表示用户已存在,并且决定后续走流程 A 还是流程 B 。我们说的不够清楚吗?

说了这么多您还没有个准确的回答,其实我心里已经有答案了。

“你难道没有发现这种情况下任何人可以通过你放出的界面来知晓任何一名用户的常用地?”,你凭什么可以知晓任何用户的常用地?你只能得到当前 ip 不是常用地,想知道常用地,必须准确的模拟出该用户的常用 ip 甚至常用设备来请求,才能得到是真实 IP 的结果。

回到标题“为什么后端开发都喜欢自己定义 responseCode ? HTTP 状态码不够用吗?”,答案就是 http 状态码根本无法代替业务状态码来使用,http 状态码真的不够用,除非你的业务够简单。

不再回复了。
no1xsyzy
2020-05-30 23:12:52 +08:00
@lscho #192 这是业务的内容,极端点说,这就是个 query,用数据体返回值即可。
你不会觉得我说只要 HTTP 状态码是说数据体一点都不要吧…… 所以说你该从头把我说的话看一遍,返回值并不是状态码。

类比到函数调用上去:
状态码决定 return value 的 continuation (比如应当被某个 try catch 拿到还是被上层调用拿到还是其他什么)而不是 return value 本身
no1xsyzy
2020-05-30 23:17:58 +08:00
@lscho #192 至于如何泄漏,简单点把所有地区模拟一遍就行了。虽然不是能够直接遍历获取的但仍然是旁路泄漏。
方便一点的,可以通过字典轻易地遍历出同 IP 的其他用户 —— 摸鱼探测器 kana ?
no1xsyzy
2020-05-30 23:34:28 +08:00
@lscho #192 回头看了下 #185 前面大段复读影响了我的阅读。没看到这句 “如何用 http 状态码表示用户名已存在。”

想了想,被问到逻辑偏掉了…… 再从头描述一下这个准则吧,“状态码即续延”。
所谓状态码、无论是 HTTP 状态码还是业务状态码,不应参与任何业务逻辑判断,而仅仅是表示 “接下来让哪个代码块来处理这个回应”
换句话说,就是 FSM 中的 “状态”。
wxF2BByt634kiAN1
2020-05-30 23:51:29 +08:00
为什么前段都喜欢把业务状态码和通信状态码混在一起
bsg1992
2020-05-31 00:48:20 +08:00
@no1xsyzy 别人说 A 你答 C 。
首先 http code 仅仅是代表传输协议的上的一种状态标识和业务没有关系。
一个业务接口通讯方式不是只有一种,如果用的不是 http 协议没有 http code 如何标识业务状态
有的业务需要根据后端返回的状态码来进行相应的操作。比如说提现场景,申请提现业务方更改了规则导致业务提现失败,需要根据相应的规则进行不同的跳转,这个时候你不用 code 做标识,难道用 msg? 还是说按照您的逻辑来说这个业务的处理方式不合理?
还有和别人进行交流的时候请不要用一些亚文化的词语和梗
no1xsyzy
2020-05-31 01:09:22 +08:00
@bsg1992 #197 “需要根据相应的规则进行不同的跳转” 不就是续延的意思吗?
我不是说了(#109 )用 Symbol 吗? code 本身就是旧时代产物,业务层面一切 code 应当由 symbol 取代,没有很好的依据随便用 code 的全部当作 premature optimization 。

亚文化词语和哏…… 我细看也只发现了个不影响整体含义的 kana ;其他有嫌疑的,比如奇美拉是希腊神话,算不得亚文化,其他也没什么亚文化,倒是可能你没文化。
back0893
2020-05-31 01:28:45 +08:00
请求确定用户名是否存在
这是不是很常见的需求
或者换成电子邮箱,你不能不去判断邮箱不重复吧
cz5424
2020-05-31 10:28:07 +08:00
不考虑后端工作量的所有假设都是伪命题

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

https://ex.noerr.eu.org/t/676678

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

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

© 2021 V2EX