有状态的 web 应用

简介

HTTP 协议是无状态的。换句话说,在你的各次请求之间,服务器是不会保留你的 “状态” 信息。

每一次请求都被认为是一次全新的请求,不同的请求之间并不知道对方的存在.这种” 无状态性 “使得 HTTP 和互联网都是 “去中心化” 的,不会轻易被人掌控。 但也是因为这种属性,使得 web 开发者在开发有状态的 web 应用时十分的困难。

当我们看看我们熟悉的 web 应用,我们会觉得这些应用大都是有状态.比如,我们登录到 Facebook 或者 Twitter ,会看到我们的用户名显示在网页上方,这表示我们的目前状态是通过了身份验证。如果我们在页面上随便点点(对服务器发起新的请求),我们并不会突然就退出登录了。 服务器返回的响应页面里依然有我们的用户名显示着,这样看来这些应用似乎都会维持它们的状态。

在本章,我们会通过讨论一下这是怎么回事,看看 web 开发者常用的实现 “有状态” 体验的技术手段。同时,也会讨论一些用于高效展示动态页面信息的技术。会讨论以下技术:

  • 会话( session )
  • Cookies
  • 异步 javascript 调用( AJAX )

一个有状态的应用

让我们来看一个有状态的应用。当你发起一个请求到http://www.reddit.com的时候,主页是这样的:

然后输入你的用户名和密码进行登录:

登录后,在页面上方你就会看到你的用户名,表示你已经成功通过身份验证。如果你刷新页面,就会向http://www.reddit.com服务器发起一个新的请求,你会看到,页面还是那个样子,你的登录状态还在。这是怎么回事呢? HTTP 不是一个无状态协议么?服务器是怎么知道你的用户名,并动态显示在页面上的?哪怕刷新页面发起新的请求也不影响你的登录状态。这种情况非常常见,我们都习以为常了。 这就是你的网络购物车在你往里加新商品的时候如何保留着你之前的选择,有时候哪怕过了几天,你也能看到你购物车里的东西。这就是 Gmail 如何认出你,并在页面上显示针对你名字的欢迎信息,所有的现代 web 应用都是这样工作的。

会话 ( session )

显然,人们可以把这个无状态的 HTTP 协议通过某种方式保持状态。在客户端(一般就是指浏览器)的帮助下,HTTP 的行为会让人觉得它会在客户端与服务器之间维护一个有状态的连接,尽管实际并没有。达到这种效果的一个办法就是, 服务器在发送响应数据给客户端的时候带一个唯一的令牌(英文叫 token,就是一串数)。随后不论何时客户端向服务器发起请求的时候都把这个令牌附加在后面,让服务器能够辨识这个客户端。在 web 开发领域我们把这个来回传递的令牌叫做会话标识符( session identifier )。

这种在客户端与服务器之间传递会话 id的机制,能让服务器创建一种各次请求之间的持续连接状态。Web 开发人员利用这种人造的状态,来构建复杂的应用程序。即使这样,每一个请求严格上来说还是无状态的,各次请求之间并不知道彼此的存在。

这种人造状态,会有几个后果。第一,必须检查每个请求,查看它是否包含会话标识符。第二,如果请求有会话标识符,也就是有一个会话 id,服务器必须检查每一个会话 id ,确保这些会话 id 是没有过期的,也就是服务器需要维护一些关于如何处理会话过期,如何存储会话数据的规则。第三,服务器要基于这个会话 id 取出这个会话的数据。最后,服务器要根据取出的会话数据重新创建应用程序的状态( 比如,一个请求对应的 HTML ),然后将其作为响应返回给客户端。

这就意味着服务器必须非常辛勤的工作,来模拟这个有状态的用户体验。每一个请求都会有一个独立的响应,哪怕这次的响应跟前一个响应没有任何区别。举个例子,如果你登录到 Facebook 上,服务器会给你一个响应,生成你看到的主页。这个响应是一个十分复杂的 HTML 页面。Facebook 的服务器会把页面上所有照片和留言的赞和评论都组合起来,然后显示在你的时间线上。生成这样一个页面的成本非常高。现在,如果你点了某个照片下面的” 赞 “链接,理论上,Facebook 会重新生成整个页面,它会把你赞过的照片的被赞数加 1,然后把整个 HTML 作为响应返回给你,尽管除了这个赞数以外大部分内容都没有改变。 庆幸的是,实际中 Facebook 使用 Ajax 代替了全页面刷新。不然的话,刷新一个页面会花费很长时间。

服务器使用了很多先进的技术来优化会话和实现安全机制,不过这些话题都超出了本书的范围,暂且放下。现在我们来聊一个常用的存储会话信息的方法: 浏览器 cookie 。

Cookies

cookie 就是在一个请求/响应周期内,服务器发送给客户端(通常就是浏览器),并存储在客户端的一段数据。Cookies 或者 HTTP cookies,就是存储在浏览器里包含着会话信息的小文件。默认情况下,大部分浏览器的 cookies 都是启用的。当你第一次访问一个网站的时候,服务器会给你发送会话信息并将其存储在你本地电脑浏览器的 cookie 里。要注意的是真正的会话数据是存在服务器上的。在客户端发起每一个请求的时候,服务器就会比对客户端的 cookie 和服务器上的会话数据,用来标识当前的会话。通过这种方法,当你再次访问同一个网站的时候,服务器就会通过 cookie 和里面的信息来认出你的会话。

我们来看一个真实的案例。用审查器看看 cookies 是如何被创建的。我们要向http://www.yahoo.com发起一个请求。要注意的是,如果你的浏览器里已经有了 Yahoo 的 cookie ,你可能需要换一个网站。

保持审查器打开(页面上右键,点击 “查看元素 “),输入这个网址,然后看看我们的请求头部:

注意,里面没有任何有关 cookies 的东西,接下来我们看看响应头部:

你会看到有个set-cookie头部把 cookie 数据加到响应里。 在首次访问这个网站的时候这个 cookie 数据会被设置。最后,我们发起一个相同的请求然后再来看看请求头部:

你会看到有个cookie头部出现了(注意这个是请求头部,就是说这是要从你的客户端发送到服务器的)。 里面的内容是上一个响应头部set-cookie的值。这一小段数据,会出现在你每一个发起的请求里,用来唯一标识你 --- 或者说的清楚点, 标识你的客户端,也就是你的浏览器。cookie 是存在浏览器里的。现在,就算你关掉浏览器,关掉电脑, cookie 里的信息也不会消失的。

现在让我们回到本章最初的那个例子,关于 Reddit 和其他 web 应用是如何在我们发起的一个又一个请求中记住我们的登录状态。记住,每一个请求都是独立的, 不知道彼此存在的。 那么问题来了,应用程序是如何 “记住” 我们的登录状态呢?如果你要跟着做, 保持审查器打开,然后按照下面的步骤来:

  1. 点击 resources 标签然后访问http://www.reddit.com
  2. 把 cookies 那部分展开, 然后点击www.reddit.com,你就能在 value 那一列看到第一次发起请求后服务器返回给我们的 cookie 了:
  3. 然后登录,你应该能看到在最后一行出现了一个唯一的会话 id 。这个会话 id 会存在你浏览器的 cookie 里,从此后你每一个到 Reddit.com 的请求都会附上这个会话 id 。

现在每一个请求都会包含这个会话 id ,这样服务器就能唯一确认你这个客户端啦。当服务器接收到一个带有会话 id 的请求,它就会根据这个 i d 去找对应的数据,在这个对应的数据里就有服务器"记住"的客户端的状态,或者说就是这个会话 id 的状态。

会话数据存在哪里?

一句话:服务器上的某个地方。有时候,存在内存里,其他时候,可能会存在某个持久化存储介质上,比如数据库或者键 / 值存储。会话数据存在哪里不是我们现在需要关心的。现在重要的是要理解会话 id 存储在客户端,它是访问存储在服务器上的会话数据的 “钥匙”。web 应用就是这样解决 http 无状态这个问题的。

还有一点非常重要,在一个会话里发出的会话 id 是唯一的,而且有一个很短的过期时间。对上面的例子来说,在会话过期后你需要重新登录。如果我们退出登录, 会话 id 就会消失。

如果你手动删掉会话 id 也是同样的效果(在审查器里,右键 cookies 然后删除它),这样就退出登录了。

简单回顾一下,会话数据是由服务器生成并存储在服务器上,会话 id 以 cookie 的形式发送到客户端上。我们还看到了 web 应用程序如何充分利用这些来模拟在 web 上的有状态体验。

AJAX

最后,我们来简单看看 AJAX 和它在 HTTP 请求/响应周期里的作用.AJAX 是”异步 javascript 和 XML “ 的简称( Asynchronous JavaScript and XML )。它的主要特点就是允许浏览器发送请求和处理响应的时候不用刷新整个页面。举个例子,如果你登录到 Facebook 上,服务器会给你一个响应,生成你看到的主页。 这个响应是一个十分复杂的 HTML 页面。Facebook 的服务器会把各种信息组合起来,显示在你的时间线上。在前面的讨论中,我们知道,为每一个请求都重新生成一次页面的成本是非常高的(记住,你的每一个动作,点个链接,提交个表单,都会发起一个新的请求)。

当使用 AJAX 的时候,所有客户端发送的请求都是异步的,就是说页面不会刷新。举个例子,当我们在 google 上搜索的时候:

  • 访问 Google 主页http://www.google.com,然后打开审查器,看 Network 标签,里面内容是空的。
  • 当你开始搜索的时候,你会在 Network 标签看到请求如潮水般发起。

很明显发起了很多请求,但是你应该能注意到,页面没有整个刷新。 然而这个 Network 标签的内容让我们看清: 每敲一个字都会发起一个新的请求,也意味着你每按一下键都会触发一个 AJAX 请求。这些请求的响应会通过一些回调来处理。你可以这样理解回调,就是你把一些逻辑存放在某个函数里,当某个条件被触发之后再回来执行你前面存放的逻辑。在本例中,当响应返回的时候,回调就会被触发。你可能已经猜到了,回调函数会用新的搜索结果去更新网页上的 HTML 。

我们不去深究回调到底是什么样的或者如何发起一个 AJAX 请求。最主要的一点要记住的是,AJAX 请求就像是普通请求:发送到服务器的请求依然跟普通请求一样有着一个 HTTP 请求该有的所有组成部分,并且服务器处理 AJAX 请求的方法跟处理普通请求也是一样的。唯一不同就是,不是通过浏览器刷新来处理响应,而通常由客户端的一些 javascript 代码来处理。

小结

本章我们介绍了一些 web 开发者用来在无状态的 HTTP 协议上构建有状态应用的技术。你学习了 cookie 和会话,以及现代 web 应用如何记住客户端的状态。也使用审查器了解了 cookies 和会话 id 。最后,了解了 AJAX 在 web 应用里展示动态内容时所扮演的角色。

时间: 2024-07-31 10:49:40

有状态的 web 应用的相关文章

Web Service中保持ASP.net的状态

asp.net|web 简介      网络程序开发者们遇到的最普遍的问题就是如何在无状态的基于HTTP协议的交互中保持状态信息.有许多聪明的办法可以解决HTTP协议的无状态问题,例如对每个请求重复发送应用程序数据包.使用HTTP认证机制来将请求映射到特定的用户.使用Cookie来存储一系列请求的状态等.在ASP.net技术中提供了一个非常有效的方案来保持状态,该方案隐藏了所有高难度的,具有挑战性的工作的细节,用户只需简单地使用System.Web.SessionState.HttpSess

ASP.NET创建Web服务管理Web服务状态

ASP.NET创建Web服务管理Web服务状态 XML Web服务在类实现派生于WebService类的XML Web服务时,可以使用和其他ASP.NET应用程序相同的状态管理选项.WebService类包含许多公共ASP.NET对象,包括Session和Application对象. Application对象提供一个储存运行在Web应用程序中的代码可访问的数据的机制,而Session对象允许数据存储在每客户端会话基础上.如果客户端支持cookies,那么可以使用cookie来识别客户端会话.

深入RESTful无状态原则

前言 在上篇RESTful基础知识中整体的介绍了RESTful架构设计思想的框架,在往后的RESTful主题博文中,我们在这个框架的基础上不断的为其填充更加深入的知识材料.  RESTful基础知识,传送门:http://blog.csdn.net/jmilk/article/details/50452595 无状态原则 Statelessness:无状态原则是RESTful架构设计中一个非常重要的原则,无状态是相对于有状态而言的.在理解什么是无状态的交互请求之前,首先我们需要了解什么是有状态,

如何创建RESTFul Web服务

想写这篇文章很久了,这是个大话题,不是一时半会就能说清楚的. 所以准备花个一星期整理资料,把思路理清楚,然后再在Team里做个sharing:) 其实RESTFul是架构风格,并不是实现规范,也不一定非要用HTTP,但鉴于HTTP的普世性和 SOA的实现基本都基于HTTP实现. 这句话只对了前一半, 实际上REST和HTTP是息息相关的,是一种Web架构,WWW是世界最大型的分布式应用,而其实现就是基于REST的web架构的设计标准,REST架构的提出者(Roy T. Fielding 2000

ASP.NET保持用户状态的九种选择(上)

asp.net 摘要:ASP.NET为保持用户请求之间的数据提供了多种不同的途径.你可以使用Application对象.cookie.hidden fields.Sessions或Cache对象,以及它们的大量的方法.决定什么时候使用它们有时很困难.本文将介绍了上述的技术,给出了什么时候使用它们的一些指导.尽管这些技术中有些在传统ASP中已经存在,但是有了.NET框架组件后该在什么时候使用它们发生了变化.为了在ASP.NET中保持数据,你需要调整从先前的ASP中处理状态中学习到的知识. 随着We

用vfp编写Web Service(二)

发布Web Service 在IIS中建立虚拟目录 这个步骤很简单,建立一个虚拟目录.设定好以后的属性页是: 图一 这里我只设定了两个属性,其他保持默认状态.设名称为:First_web_service,设本地路径为DLL所在路径,这里是:D:\VFP7_Web_Service. 在Visual FoxPro 里发布 Web Service 工具-〉向导-〉Web Services 图二 弹出如下界面: 图三 这里,COM Server里,我们选择刚才编译的那个DLL. 为了获得更多信息,按"A

ASP.NET MVC: 构建不带Web窗体的Web应用程序

本文讨论: 模型视图控制器模式 创建控制器和视图 构建窗体和回发 控制 器工厂和其他扩展点 本文使用了以下技术: ASP.NET 我 从事专业开发迄今为止已有 15 年,在此之前,我利用业余时间从事开发至少也有 10 年了.与我这一代的大多数人一样,我是从 8 位计算机起步,然后转用 PC 平台的.随着计算机的复杂性日益增加,我编写的应用程序涵盖了从小型游 戏到个人数据管理再到控制外部硬件的各项功能. 不过,在我职业生涯的前半段,我编写的所有软件都有一个共同点:即,都是运行在用户桌面上的本 地应

Web交互设计中“灰色调”的8类应用

在进行Web的交互设计中,颜色信息的传达也是不可或缺的一部分.我们常会发现许多"灰色"的应用,他们的出现总是不动声色而又恰如其分,维持了整个页面的平衡与统一.本文将从一些实际案例出发,阐述"灰色"在Web交互设计中的8类应用. 首先让Mr.Gray 来做个简单的自我介绍吧: 狭义的 Mr.Gray 狭义的Mr.Gray, 是指没有色相与纯度,只有明度,将黑色和白色混和而成的一种中间色. 依据不同分类方法可大体分为浅灰与深灰两种,亦可分为暖灰与冷灰. 相对来说,其特征

如何缓解Web应用程序威胁 缓解Web应用程序威胁的方法

现在几乎所有企业都会在互联网上建立网站,他们不仅通过网站提供信息,而且还通过Web应用程序.博客和论坛与他们的客户进行互动.从网上零售商的互动婴儿注册表,到电子交易网站的投资计算器,或者软件供应商的互动支持论坛,企业每天都会产生新的Web应用程序来使获取信息. 以业务为中心的Web互动迅速发展也带来了新的信息安全威胁,而企业以前的静态网页并没有这些威胁.这些威胁主要是针对Web应用程序,包括补充的Web服务器.数据库和其他支持基础设施. 在本文中,我们将讨论Web应用程序面临的最严重的威胁以及安