在请求中传递SessionID被普遍认为是unRESTful的,而将用户的credentials包含在每个请求里又是一种非常RESTful的做法。这样一个问题经常会造成困扰。本文就REST的一些概念进行了探讨,解释了REST架构中的状态,无状态(stateless),以及两种状态的区别

  

  今天早上在Yahoo的邮件列表里看到一篇颇有意思的讨论,标题为RESTful vs. unRESTful: Session IDs and Authentication(51CTO编者注:意为REST对非REST,Session ID与验证)。文中让发起讨论的朋友大惑不解的是这样一个问题:为什么在请求中传递SessionID被普遍认为是unRESTful的,而将用户的credentials包含在每个请求里又是一种非常RESTful的做法。看了他接下来对于REST架构风格中"statelessness"属性的理解后,我觉得有必要对这个经常会被人误解词汇以及相关概念做一个简要的整理,希望能够通过这篇随笔解释清楚什么是状态,为什么要实现无状态,以及REST风格架构中的两种状态的区别,最后我会从我的理解出发来回答作者提出的这个问题。

  首先,一个Web应用程序协议的“状态”在通常指的是为两个相互关联的用户交互操作保留的某种公共信息,它们常常被用来存储工作流或用户状态信息等数据。这些信息可以被指定不同的作用域如page,request,session或全局作用域,而存储他们的责任也同样可以由Client端或Server端负责。虽然存储状态为企业软件开发带来了诸多便利,但是它也给分布式系统的其他方面带来了许多限制,比如在负载均衡方面,在有状态的模式下,一个用户的请求必须被提交到保存有其相关状态信息的服务器上,否则这些请求可能无法被理解,这也就意味着在此模式下服务器端无法对用户请求进行自由调度。于此相关的另一个问题是容错性,倘若保有用户信息的服务器宕机,那么该用户最近的所有交互操作将无法被透明地移送至备用服务器上,除非该服务器时刻与主服务器同步全部用户的状态信息。此外,由于HTTP本身不是一个有状态的协议,开发人员必须通过模拟实现状态的钝化与激活等。于是为了克服这些不足,无状态(Statelessness)架构风格属性受到了广泛关注。

  无状态指的是任意一个Web请求必须完全与其他请求隔离,当请求端提出请求时,请求本身包含了相应端为相应这一请求所需的全部信息。这一约束的出现改善了分布式系统的可见性、可靠性以及可伸缩性,具体的介绍可以参考Roy T. Fielding博士的论文,这里就不哆嗦了。这些从整个系统角度来看无状态似乎过于抽象,那么对于用户来说,怎么感觉的有状态与无状态的差别呢。简单的方法是浏览器的后退按钮,如果一个网站期望用户以A->B->C的流程来交互,而在执行至B时回退的话,那么系统很有可能不是按照其所期望的方式运行,因为用户的状态可能被不可逆地修改了。反过来,搜索引擎(我指的是普通意义上的搜索引擎,而不是根据用户搜索历史个性化了的)是一个无状态架构的范例。任何用户可以在浏览器地址栏中输入http://www.google.com/search?q=RESTful&start=100来获得从第一百条开始的关于RESTful的记录,并且当Google摩洛哥服务器瘫痪时,相关用户请求会被透明地移送至其他服务器。

  一切似乎很明了,那么是什么导致了那位朋友的误解呢,答案是RESTful架构对于state的两个不同的解释: 应用状态(Application State)和资源状态(Resource State)。应用状态指的是与某一特定请求相关的状态信息,而资源状态则反映了某一存储在服务器端资源在某一时刻的特定状态,该状态不会因为用户请求而改变,任何用户在同一时刻对该资源的请求都会获得这一状态的表现(Representation)。RESTful架构要求服务器端不保有任何与特定HTTP请求相关的资源,所以应用状态必须由请求方在请求过程中提供。那么再回到那个邮件列表中的问题,为什么传递一个session ID是违背REST架构风格而传递user credentials却不是。我想作者的疑惑源于他没有分清什么是有状态和无状态的架构属性,而认为“传递某种表示状态的信息”到服务器便是“有状态”的表现。其实有状态和无状态与请求本身没有多大关联,重要的是状态信息是由请求方还是响应方负责保存。在Session ID可以被认为是一个用来标识某一会话状态的Key,将其传递给服务器端意味着这样一个请求:“请帮我取出这个状态信息”,也就是说这个请求假设响应方保有着状态信息。由于与某一特定请求相关的状态属于应用状态,而RESTful架构要求任何此类状态由请求方负责提供,所以传递Session ID被认为是unRESTful的做法。反过来,user credential作为一种应用状态,是被期望由请求方提供的,所以在请求中传递user credentials(姑且忽略安全性问题)是符合RESTful架构规范的。

  这篇随笔或多或少散发着某种纯粹主义的味道,但我觉得有些概念是值得玩味的。任何一种架构风格的出现都有其期望的,对现有方案的改进或期望克服的问题。作为REST来说,它所期望的是组件的可伸缩性,组件的独立部署,接口统一等特性,而无状态作为实现这组需求的一个特性,个人认为是有必要清楚了解并实际开发过程中落实的。

  RESTful 架构中需要分离出 OAuth 服务,将所有的应用认证统一管理,后续的每次请求都需要通过授权服务,再转向到服务器,进行权限管理,这样,就可以将应用的验证状态分离出来,使得后端分布式变为无状态方式,之后的负载或者其他的处理,更加简单,但是,分离出来,架构复杂度提升,维护和开发、测试的成本增加

原文地址:http://developer.51cto.com/art/200906/129424.htm

对于REST中无状态(stateless)的一点认识(转)的更多相关文章

  1. 对于REST中无状态(stateless)的一点认识

    今天早上在Yahoo的邮件列表里看到一篇颇有意思的讨论,标题为RESTful vs. unRESTful: Session IDs and Authentication(51CTO编者注:意为REST ...

  2. 有状态(Stateful)与无状态(Stateless)

    1.有状态(Stateful): 有数据存储功能.有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,类里面有成员变量,而且成员变量是可变的,是非线程安全的.在不同方法调用间 ...

  3. 关于Spring Security中无Session和无状态stateless

    Spring Security是J2EE领域使用最广泛的权限框架,支持HTTP BASIC, DIGEST, X509, LDAP, FORM-AUTHENTICATION, OPENID, CAS, ...

  4. (转)Spring Bean Scope 有状态的Bean 无状态的Bean

    有状态会话bean   :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”:一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束.即每个用户最初都会得到一 ...

  5. 线程安全,有状态,无状态的对象<转>

    进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.另外 ...

  6. NHibernate使用无状态Sessions

    NHibernate 3.0 Cookbook第三章,Using stateless sessions的翻译. 当要处理大量的数据,你通常可能会使用更"底层"的API来改善性能,在 ...

  7. 什么是Http无状态?Session、Cookie、Token三者之间的区别

    一.什么是HTTP无状态? 1.1定义: HTTP无状态协议,是指协议对于交互性场景没有记忆能力. 1.2举个例子: 在点击一个纯的html网页,请求获取服务器的html文件资源时,每次http请求都 ...

  8. 有状态 无状态 stateful stateless monolithic architecture microservice architecture 单体架构

    为什么游戏公司的server不愿意微服务化? - 知乎 https://www.zhihu.com/question/359630395 我大概说了,方便测试,方便维护,方便升级,服务之间松耦合,可多 ...

  9. Blazor中的无状态组件

    声明:本文将RenderFragment称之为组件DOM树或者是组件DOM节点,将*.razor称之为组件. 1. 什么是无状态组件 如果了解React,那就应该清楚,React中存在着一种组件,它只 ...

随机推荐

  1. 【LeetCode】144. Binary Tree Preorder Traversal (3 solutions)

    Binary Tree Preorder Traversal Given a binary tree, return the preorder traversal of its nodes' valu ...

  2. 快速掌握activity的生命周期

    activity的生命周期不管是在面试还是在工作中我们都会经常遇到,这当然也是非常基础的,基础也很重要哦,学会activity的生命周期对我们以后开发更健壮的程序会有很大帮助.下面来看一下Activi ...

  3. Form_如何通过标准功能查找数据源(概念)

    2014-06-01 Created By BaoXinjian

  4. Scanner类nextInt方法的使用注意点

    一.先看一段正常的代码 1. 一段用Scanner捕获键盘输入的代码: Scanner sc = new Scanner(System.in); // 先读取键盘输入的字符串 System.out.p ...

  5. Spring注解 强大了个强大--详解注解方式

    好文章:http://tonyaction.blog.51cto.com/227462/83874/ http://www.ibm.com/developerworks/cn/java/j-lo-sp ...

  6. mysql InnoDB 的行锁

    表的引擎类型必须为InnoDB才可以进行此操作. 相关链接:http://www.cnblogs.com/CyLee/p/5579672.html 共享锁:单独运行前两句,然后新建一个会话使用第三句. ...

  7. python标准库介绍——18 StringIO 模块详解

    ==StringIO 模块== [Example 2-8 #eg-2-8] 展示了 ``StringIO`` 模块的使用. 它实现了一个工作在内存的文件对象 (内存文件). 在大多需要标准文件对象的地 ...

  8. introduction to python for statistics,analysis笔记3

    一.产生数组和矩阵 1.linspace(start,end,number),产生在start和end数之间number个数 >>> x = linspace(, , ) >& ...

  9. linux centos7 常用命令【systemctl替换service】

    虽然linux的命令很多都是相同的,但是新版的centos 7 上面与以前的有些命令还是有所不同,不过还好,有提示.所以就在百度上面搜索了以下,作为记载,以后方便查看: centos7 上面启动服务以 ...

  10. cocos2dx 3.3将坐标由父空间转化到局部空间

    设在node的父空间内有一点p,要求其转化到node局部空间后的坐标p_local,代码如下: node->getNodeToParentTransform();//in order node- ...