关于 REST 中的“无状态”的一个疑问。

2020-12-24 00:39:54 +08:00
 mitu9527

下面的内容引自 REST 论文原文:

We next add a constraint to the client-server interaction: communication must be stateless in nature, as in the client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3), such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client.

重点是最后一句,翻译过来就是“因此,会话状态完全保存在客户端上”。虽然出自官方,但我对此还是有疑问:

把会话数据存在客户端,也就是使用所谓的“客户端会话”真的算是“无状态”么?

我又去读了很多关于“无状态”的文章、帖子和回复,我看到不少人说这种确实是“无状态”,但我个人总觉得不对。客户端会话数据也是由服务端生成,最终也是由服务端读取,只不过没有被保存在服务端,而是被保存到了客户端,所以它和常见的“服务端会话”的区别只是存储的地方不一样(这种“去中心化”确实有它的好处,但缺点也不少),但作用完全是一样的,难道不是么?

把会话数据从客户端传给服务端,然后服务端读取传过来的会话数据并进行使用,这不也是在读取本次交互过程(或者说会话)中前面某个请求所产生的数据么?那请求和请求之间还算是互相独立么?说好的“人生只如初见”呢?

现在的我觉得如果要“无状态” ,就绝对不应该有“会话”这个概念,不论是“服务端会话”还是“客户端会话”,都不应该存在,感觉使用“客户端会话”来符合“无状态”有点像掩耳盗铃似的。

最后在重复一遍问题:把会话数据存在客户端,也就是使用所谓的“客户端会话”真的算是“无状态”么?

5393 次点击
所在节点    程序员
82 条回复
Jooooooooo
2020-12-24 00:43:07 +08:00
又要提那一句: 少纠结定义问题

有具体问题直接具体分析
GeruzoniAnsasu
2020-12-24 00:44:02 +08:00
such that each request from client to server must contain all of the information necessary to understand the request

划重点
这是所谓的无状态,比如登录与否的状态不应由连接来保持,而是每个请求中都含有完整的鉴权信息
mitu9527
2020-12-24 00:47:02 +08:00
@Jooooooooo 我也不想纠结这个问题,只不过看到好多人的想法和自己不同,连原论文都和自己的想法不同,三人成虎啊,我担心自己是不是哪里没搞明白,所以才来提问。
Jooooooooo
2020-12-24 00:48:33 +08:00
@mitu9527 你能弄明白为什么要有无状态, 会话这些东西. 及其特性带来的好处就行了.
fengchang
2020-12-24 00:49:36 +08:00
我觉得算,你这个问题很奇怪
mitu9527
2020-12-24 00:53:49 +08:00
@fengchang 理由是?你不觉得都已经有会话状态了,还能说再说是“无状态”么?
mitu9527
2020-12-24 00:57:11 +08:00
@GeruzoniAnsasu 所以你的观点是?算还是不算?
GeruzoniAnsasu
2020-12-24 01:01:10 +08:00
@mitu9527 我的观点是



























我遵循“智能 REST*互联网+技术”
这个技术的核心要义是 Each request from client to server must contain all of the information necessary to understand the request.
Bromine0x23
2020-12-24 01:02:25 +08:00
https://www.ics.uci.edu/~fielding/pubs/dissertation/net_arch_styles.htm#sec_3_4_3

3.4.3 Client-Stateless-Server (CSS)
The client-stateless-server style derives from client-server with the additional constraint that no session state is allowed on the server component. Each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is kept entirely on the client.



https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_3

5.1.3 Stateless
We next add a constraint to the client-server interaction: communication must be stateless in nature, as in the client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3), such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client.
YouMoeYi
2020-12-24 01:06:56 +08:00
老哥我觉得你可能搞错了无状态所形容的对象。我们说 HTTP 是无状态的,是指 HTTP 在两次连接之间不能保存状态而不是客户端或者服务端不能保存状态,客户端和服务端的会话就是用来解决 HTTP 无状态所带来的缺陷。
fengchang
2020-12-24 01:13:24 +08:00
@mitu9527 REST 是一项服务端的技术,它的范围就到 API,它不关心你是用浏览器、客户端、curl 还是 Postman 访问。定义这个事情当然是定义者说了算,他的定义就是 REST 的服务端不保存状态,你为啥非要说客户端也不能保存会话才算无状态?

你可以用 curl 访问 RESTful 的服务,然后把 cookie 记在脑子里,每次输入命令的时候打出来,这样客户端也无状态了。那是不是可以继续问“脑子里有会话真的算是无状态吗”?
lihongming
2020-12-24 02:00:34 +08:00
无状态是相对于以前的 session 来说的,以前登录状态可以保存在 session 里,服务端拿着客户端传来的 session id 就知道状态了。

而在横向扩展司空见惯的云计算时代,各服务器之间同步 session 是一个成本很高的任务,所以状态就放在客户端了。这思想有点依赖注入的感觉——你需要一个状态,所以我就在调用你的时候给你个状态。服务端根据签名算法验证一下客户端状态的真伪,就可以直接用了。
ysc3839
2020-12-24 02:38:51 +08:00
个人理解这里说的“无状态”是指服务器无 session 状态。不是 HTTP 那个无状态,也不代表服务器不使用数据库保存其他信息。
原因就是楼上所说的不同服务器同步 session 成本高。理论上也可以把 session 存在数据库中,但是成本也是比存客户端高。
yzbythesea
2020-12-24 04:28:07 +08:00
stateless 指的是你这个 API call 不需要知道任何 之前 API call 的内容和状态,是独立的。
zjsxwc
2020-12-24 08:24:15 +08:00
服务端保存状态数据,客户端没有保存状态数据,就是 statefull,比如对于用户登录状态数据来说,我们常见的客户端请求使用 sessionId 模式。


服务端尽可能少保存状态数据,客户端保存状态数据,就是 stateless,比如对于资源数据来说,我们常见的在 url 里包含资源 id,每次访问这个 url 就是同一个资源内容,在客户端里面保存用户访问资源历史,而不是在服务端里面保存用户访问资源历史。
airfling
2020-12-24 08:28:44 +08:00
所有的请求都带 bearr token,token 里面自己带了加密的用户信息和有效时间
whileFalse
2020-12-24 08:37:26 +08:00
我司的做法是,前端 Node 服务有 Session 状态,会用 Session 保存用户 ID,可能还有其他用户信息。
后端 Java 服务就没有登录状态这说法了。Node 传过来哪个用户的行为后端就相信是这个用户。

LZ 引用的论文是不是要把用户 ID 甚至用户权限都放在短效 JWT 里面呀。
mitu9527
2020-12-24 09:09:08 +08:00
@whileFalse 我个人反对把用户 ID 和用户权限放在 JWT 里面,因为这时候 JWT 本质上就是我说的客户端会话而已,不过好多人都说这么做可以,我质疑的就是这种用法。

我觉得正确的用法应该大概是这样,客户端提交用户名和密码向服务端申请 JWT,JWT 的 payload 中只包含一个令牌和一个过期时间,后续请求都把 JWT 传到服务端,服务端验证通过 JWT 后就通过 payload 中的令牌找到通过认证的用户即可。至于一次交互内之前产生的临时数据或者说状态,应该存放在客户端的本地存储中,只要发起请求时,把服务端需要的参数从本地存储中拿出来放到请求中即可。
mitu9527
2020-12-24 09:11:28 +08:00
@airfling 嗯,这个肯定没错,不过有些人认为还可以把比如用户 id 、用户权限等会话数据放到 token 中,虽然很方便,但这时候 token 就变成客户端会话了,我觉得这种做法不合适。
mitu9527
2020-12-24 09:16:08 +08:00
@lihongming 你说的这种用法,如果只是登陆状态这一种状态,我觉得没问题,但是如果把 token 中塞满以前保存在服务端会话中的那些会话数据呢?就比如说用户权限数据,以前经常是保存在服务端会话中的,如果现在把它挪到客户端合适么?

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

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

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

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

© 2021 V2EX