【Web 服务】深入理解无状态协议、HTTP 与 web 会话
1. 什么是状态(state)?
状态可以简单地理解为事物在某一个时间点上的特征表现。事物在不断的发展、运动和变化,这样才会有状态,这样的状态才会有意义!绝对的静止就是黑洞,就不会有状态,也不会产生信息!
生老病死,花开花谢,春去秋来,都是事物状态的变迁!
软件领域与状态相关的概念有很多,比如生命周期,状态机,状态迁移,无状态服务,无状态协议,等等。
2. 无状态协议(Stateless protocol)
通信协议分为有状态(stateful)协议和无状态(stateless)协议,无状态协议不存储交互信息,通信中的一方不关心另一方的状态,也无需对结果进行确认。比如 UDP 协议就是无状态,TCP 协议就是有状态;HTTP 是无状态的,FTP,SSH 是有状态的。
无状态(stateless) vs 无会话(no session) vs 无连接(connectionless)——这三个概念本质上讲的是同一件事,只是层次和关注点不同而已。会话是应用或服务层面的概念,指代服务运行的上下文;连接是数据传输的通道,面向连接/无连接则表明了连接的特点。
比如 TCP 是面向连接的有状态协议,其“可靠性传输”的本质就是一种形式会话管理。
3. 无状态的特征
无状态设计能大大的简化服务器的复杂性,因为状态管理是一件复杂的事情,要建立连接,创建会话,同步信息,释放资源,异常与错误处理等等。而无状态就简单多了,一件是一件,一码归一码。
但要保证请求的独立性,就必须在请求体中携带该请求所需的全部信息,服务端解析请求信息,处理并相应。
设计的本质就是取舍,在时间与空间之间取舍,在 CPU 与 IO 之间取舍,在繁与快、简与慢之间取舍,在效率与成本之间取舍…
当网络带宽是通信的最大瓶颈时,设计人员关注的重点是如何对信息进行编码,进行压缩,绞尽脑汁的筛除掉信息中的冗余数据,那个时代的通信协议,每个比特都要发挥它的价值。当带宽无线富足时,设计人员就慢慢将关注点转移到业务上,转移到开发效率上。
4. HTTP
HTTP 是典型的无状态协议,每个 HTTP 请求都是独立的,隔离的,自解释的!
简单地说,就是 HTTP 协议本身不支持 Session,是无状态的,不需要登录。FTP 协议就是有状态的,在信息交互之前要登录,创建本次交互对应的会话,还可以进行认证、鉴权等。
每一个 HTTP 请求(非长连接模式),都包含连接的建立和关闭。
但这并不意味着 HTTP Server 只能提供无状态的服务!IP 协议是无状态的,但基于 IP 的 TCP 就是有状态的。协议栈,或者服务栈,都是层次化的,在无状态协议上添加新的会话机制,便可以提供有状态的服务。
5. Web 会话
在互联网时代,我们每时每刻都在与 Web 服务器打交道,有些服务是有状态的,有些是无状态的。这里涉及到了两个问题,一是 Web 服务需不需要会话?二是如何实现 Web 会话。
不同的场景,有不同的需求;不同的需求,会产生不同的方案!比如我百度或谷歌一下,这个需求本身是无状态的。我搜索一下喜马拉雅山的高度,难道你还要问我是哪里人?多大了?姓甚名谁?那不就搞笑了吗!当然从百度的角度看,为了优化搜索,或者广告推广,即使客户没有会话需求,百度在后台也默默的进行会话管理。
另外,有些服务是有状态的,比如去视频网站看电影,vip 会员免广告,这就涉及到会话了,你不登录/认证/鉴权,人家怎么知道你是不是会员呢?
总体而言,3 种常见的实现 Web 应用会话管理的方式:
- 基于 server 端 session 的管理方式: JSESSIONID,PHPSESSIONID
- cookie-base的管理方式
- token-base的管理方式
Web Session 是建立在 HTTP 层之上的服务管理机制,在实现 Session 机制时,必然会用到 HTTP 的某些特性,比如 cookie, 当然也可以实现不依赖于 cookie 的 Session 机制,尤其是 cookie 有可能会被人为的禁止;另一种技术是 URL 重写技术,就是把 session id 直接附加在 URL 路径的后面。
在设计会话管理的机制中,常常要考虑会话资源的内存消耗,分布式与集群部署时的数据共享,跨域,服务端复杂性,信息传输的安全性等问题。
Web Session 是服务器的机制,没有统一的规范,不同的 Web 服务器有不同的实现。Java 的 Servlet,Python 的 wsgi,以及 CGI 都有各自关于 Session 管理的规范。
5. 会话,登录,认证
有状态的服务一定有会话管理,但不一定需要登录。
会话管理是登录与认证的前提和基础。
一些相关的概念:
- 身份识别: identify,登录与认证/鉴权,第三方登录
- 会话: session
- 认证: authenticate,
- 单点登录: sso
- CAS:Apache 认证服务解决方案
- SAML
- OAuth2.0
- AAA
无论是 Web 端还是移动端,第三方应用账户登录已经成为了标配。
实现单点登录,分为两个阶段:
- 阶段一:所有子系统共享用户身份信息,也就是所有的身份信息都存储在同一处,比如 ldap server,或者某个数据库中,那么可以使用同一账户登录所有的子系统。本公司的 jira,邮件系统,OA,日志,SVN … 所有的账户信息都是独立的,更无需谈论什么单点登录了。
- 阶段二: 只要登录了任意一个子系统,再访问其它子系统时,就无需登录了,此之谓单点登录。
单点登录的三驾马车: OpenID, OAuth, SAML
OpenID
Google, Yahoo, PayPal 等支持 OpenID, OpenID-Connect 是认证协议。
使用场景: 商用应用的单点登录
OAuth2
其实是个授权的标准协议,也可以认为是基于授权的“伪认证”。
使用场景: API 授权
SAML
- Security Assertion Markup Language
- 可用于单点登录
- IDP: Identity Provider, 身份鉴别服务器,主站
- SP: Service Providers, 在主站中注册过的应用服务器
使用场景: 企业级单点登录,但是对于移动端支持不是很好