关于 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.

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

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

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

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

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

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

5409 次点击
所在节点    程序员
82 条回复
mitu9527
2020-12-24 09:26:38 +08:00
@ysc3839 那就是说,你认为只要服务端无会话状态,比如把会话状态存在客户端,就算 REST 的“无状态”了,对么?

我个人的想法是,这些会话数据由服务端产生,最终也是由服务端读取使用,本质上还是服务端在用,只不过被存放在客户端上了而已。

如果客户端自己把交互过程中的状态存在自己的本地存储上,然后在向服务端发送请求时,自己从本地存储中选用服务端需要的状态,再和请求一起发给服务端,这才是真正的“无状态”。客户端自己存放,自己选取使用,服务端只做接收方。
mitu9527
2020-12-24 09:29:45 +08:00
@Bromine0x23 这两段实际上我都看了,只不过觉得意思是一样的,所以我就引用了一段。所以你的意思是把交互状态放到“客户端会话”中算是“无状态”了?
wangritian
2020-12-24 09:33:38 +08:00
有时间不如研究会话安全
mitu9527
2020-12-24 09:41:56 +08:00
@fengchang 我只是觉得,客户端会话的状态是有服务端生成,最后也是由服务端读取使用,这种不能算“无状态”。

我觉得客户端自主生成状态,然后放在自己的本地存储中,然后再根据下次调用的 api 需要什么数据,再从本地存储中取出来,这才是“无状态”,服务端根本就不知道“状态”为何物,只知道客户端会把我要的数据都发给我,我直接用就行了。

服务端不知道“状态”为何物 != 服务端不在乎“状态”存在哪里。
whileFalse
2020-12-24 09:43:14 +08:00
@mitu9527
> 我个人反对把用户 ID 和用户权限放在 JWT 里面,因为这时候 JWT 本质上就是我说的客户端会话而已
> 我觉得正确的用法应该大概是这样,客户端提交用户名和密码向服务端申请 JWT,JWT 的 payload 中只包含一个令牌和一个过期时间,后续请求都把 JWT 传到服务端,服务端验证通过 JWT 后就通过 payload 中的令牌找到通过认证的用户即可

没明白你这个令牌什么意思。我觉得他要不是包含用户 ID,要不就是个 session key 。如果它就是 session key,那为什么不直接用 session,何必弄 JWT 。

你还是没理解 JWT 和 Session 的区别。Session 的好处是可以随时修改随时吊销。JWT 的好处是可以离线验证,因此微服务不需要总是和中央权限系统交互。
PetterZhu
2020-12-24 09:45:30 +08:00
http 是短链接,tcp 没有一直保持连接,无状态应该是指这种的无状态吧, 怎么扯到 cookie,session 呢?
mitu9527
2020-12-24 09:46:03 +08:00
@wangritian 我现在认为如果要遵循 REST,会话数据就不应该由服务端生成,然后放在客户端,然后还绞尽脑汁想着怎么才能不泄露、篡改、伪造和重放。
kop1989
2020-12-24 09:48:39 +08:00
@mitu9527 #24
从我的理解来看。

1 、“状态标识”是必然要存的。
2 、“状态标识”不存在“被调用方”(绝大多数情况的服务器端),就一定存在调用方(绝大多数情况的客户端)。
3 、服务器端其实是知晓,且需要处理“状态标识”的,否则你相同客户端调用两个 api,逻辑怎么贯通?

综合上文 1 、2 、3 。服务器端不存“状态标志” == 无状态 == REST
msg7086
2020-12-24 09:54:12 +08:00
想法反了。

可以这么理解:
恰恰是因为客户端保存了会话,所以才能做到无状态。
如果客户端不保存会话,那么请求就无法做到无状态。

比如说你要做一个在线商城,有购物车组件。
如果购物车存在服务器端,那么当你有很多服务器的时候,CDN 派发到另一个服务器,那你购物车就空了,因为你的会话在另一台服务器上不可用。如果是客户端会话,那么换了一台服务器以后,也可以直接从客户端发来的会话里读取数据。

当然,你也可以把购物车存在中央存储区里(例如数据库或者内存数据集群等),但是这样又会增加服务器间的通讯量,以及把更多的压力放在一个单一服务(数据库)上。

无状态的话,客户会话是由应用程序服务端处理的,而应用程序服务器是可以大量横向扩展的,人多的服务你堆个一万台机器上去就结了。

数据库你咋堆服务器。
mitu9527
2020-12-24 09:55:20 +08:00
@kop1989 问题就是,现在我认为在 REST 下,两次请求就不应该用会话这个概念来贯通,应该是是毫无关系才对。
mitu9527
2020-12-24 10:00:49 +08:00
@msg7086 你说的我基本上都明白,但我的意思是“状态”不应该由服务端生成(做决定),服务端每次只返回数据给客户端就可以了(服务端根本不在乎之前请求发生过什么),客户端接收到数据之后,要自己决定要把什么“状态”缓存在客户端本地缓存中,然后下次发起 api 调用时,自己决定该从客户端本地存储中读取哪些必须数据并和请求一起发给服务端。不是服务端决定该把什么“状态”缓存在客户端。
kop1989
2020-12-24 10:03:36 +08:00
@mitu9527 #30

毫无关系理论上可行,但性价比太低。

毫无关系就需要客户端提供一切当前状态的业务信息,供服务器端来进行逻辑判断。
这就极大的加剧了每个接口服务器端和客户端之间的信息吞吐量。

而且也加剧了程序的开发复杂度和耦合度。

举个例子,你考试写名字 or 身份证号就可以了。就是因为你(客户端)和学校(服务器端)之间,通过考试报名实现了预设信息沟通(登录)。

否则你每参加一科考试,都需要填写巨量的个人身份信息。这样非常的不环保,也增加了你填错的可能性。更严重一点会造成你当场的考卷作废。
msg7086
2020-12-24 10:03:54 +08:00
@mitu9527 会话数据不是缓存。
甚至很多时候这个会话是对客户端加密的,只有服务器能读取其中的内容。
对客户端来说,会话就只是一坨他看不懂的东西而已。
mitu9527
2020-12-24 10:09:22 +08:00
@msg7086 那就是了,完全是服务端在把控的东西(只不过存在客户端),还能说服务端“无状态”么?
Vegetable
2020-12-24 10:13:01 +08:00
你这是在说“我的定义和你不一样,所以你错了”

你干脆说 stateless 并不应该翻译成无状态算了,因为了 less 是少,而不是无。
wangritian
2020-12-24 10:16:50 +08:00
@mitu9527 抱歉对 REST 不是很了解,抛开定义不谈,业务接口不可能无状态对吧,你不能让用户干什么都提交账号密码。下一步就是客户端保存 sessionId 和完整加密数据之间的博弈了,所以我觉得无状态是怎么定义的不重要,讨论最佳安全策略是最重要的。如果一定要讨论,我认为是 REST 本身设计就是无状态的,每个请求各自独立,不像 tcp 或是 NAT 那样需要依赖前次请求保存的状态;所谓状态是作为 REST 的用户在业务层面加上去的,跟协议本身其实无关。
SjwNo1
2020-12-24 10:18:15 +08:00
很多我们用 JWT 发挥了和 Session 一样的功效,JWT 不能随时吊销,两者都需要 db 支持,因此有人说在这方面没有真正意义上的无状态
ysc3839
2020-12-24 10:26:11 +08:00
@mitu9527 是的。按我的理解,REST 的这种无状态还是会允许使用数据库的,那数据库中的数据也可以认为是一种“状态”,这就跟“无状态”矛盾了。所以这里的无状态应该理解为没有 session 。
suenlai
2020-12-24 10:33:23 +08:00
@GeruzoniAnsasu 我也是这么理解的.
msg7086
2020-12-24 10:34:08 +08:00
@mitu9527 当然是。
还是那句话,恰恰因为服务器把数据存在了客户端才让他成为了无状态服务器。

就像素鸡,本质上是豆制品。你突然冒出一句,连鸡都没有,还能说这种食材叫素鸡吗!就比较尴尬了。人家就是这么定义的,你觉不觉得不影响别人定义。

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

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

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

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

© 2021 V2EX