从Ajax到WebSocket

当需要前端频繁的请求后端数据的时候,比如说数据的实时显示,这种情况下产生问题的核心原因是:服务器知道数据什么时候更新,但浏览器不知道。
这种情况下,即使对于强大的Ajax,也是一个难以解决的问题。

解决方案1:频繁轮询

当我们手中只有ajax工具的时候,我们往往会选择这样的解决方式:
通过设定定时器,以一个固定的频率(比如1秒/次)将ajax请求打到服务器查询新的数据。如果后端有数据,则返回新数据,如果没有,就返回空。

这样的协议在请求不需要那么频繁并且用户量小的时候,勉强能用。很明显,该协议有大量的请求被浪费了,并且服务器做出了大量无效的响应。

解决方案2:长轮询

长轮询其实是频繁轮询的一个妥协,他与频繁轮询一样,也是需要前端不断的打请求,但是如果服务器没有新数据,那么服务器对前端的请求不做响应。

该方法会出现下面三个问题:

  1. 如果浏览器在服务器响应之前,有新数据发送到服务器怎么办?
    浏览器必须创建一个新的并行请求,或者终止当前请求然后创建新的请求。
  2. TCP和HTTP连接都指定了连接超时,所以服务器和客户端必须周期性的关闭和重建连接。
  3. HTTP/1.1规范中存在着强制的连接限制。浏览器最多只允许同时创建两个到相同主机名的连接。如果一个连接长期连接到服务器等待数据推送,那么它将减少一般可用于从服务器抓去web页面、图形和其他资源的连接。

在过去几年,长轮询得到了广泛的应用,通常被称为Comet。

解决方案3: 分块编码

持续连接的问题:对于非持续连接,浏览器可以通过连接是否关闭来界定请求或响应实体的边界;而对于持续连接,这种方法显然不奏效。有时,尽管我已经发送完所有数据,但浏览器并不知道这一点,它无法得知这个打开的连接上是否还会有新数据进来,只能傻傻地等了。
为了不让浏览器等待,响应对象一般使用一个Content-Length:n头来告知浏览器这个数据有多长。浏览器可以通过 Content-Length 的长度信息,判断出响应实体已结束。
Content-length引入的新问题:由于 Content-Length 字段必须真实反映实体长度,但是对于动态生成的内容来说,在内容创建完之前,长度是不可知的。这时候要想准确获取长度,只能开一个足够大的 buffer,等内容全部生成好再计算。但这样做一方面需要更大的内存开销,另一方面也会让客户端等更久。
我们需要一个新的机制:不依赖头部的长度信息,也能知道实体的边界——分块编码(Transfer-Encoding: chunked)。

分块编码非常类似于长轮询,它利用了HTTP/1.1的特性:服务器可以在不声明内容长度的情况下响应请求。
响应在不使用Content-Length:n头时,可以使用Transfer-Encoding:chunked头。这样将告诉浏览器 响应对象将被“分块发送”。

利用这一特性,在开始的时候创建一个连接,只用于接受服务器发送的时间,来自服务器的每一个块都是一个新事件,它们将出发JavaScript XMLHttpRequest对象的onreadystatechange时间处理器的调用。

尽管不如长轮询那么频繁,但是连接仍然需要更新。

解决方案4: Applet和Adobe Flash

在演变的过程中,人们渐渐意识到这些解决方法所做的其实是通过单个连接来模拟全双工通信。简单来说,Ajax和XMLHttpRequest无法完成该任务,一个更流行尽管更短命的解决方案是Java Applet或者Adobe Flash。

开发者将创建一个含有1个像素的普通透明Applet或者Flash影片,并内嵌在网页中,然后这个插件将创建出连接到服务器的TCP Socket连接(而不是Http连接)。这种方式消除了HTTP协议中的制约限制。

该协议在单个连接上实现了真正的全双工通信,并消除了例如超时和兵法连接限制这样的问题,但也带来了很高的代价:使用第三方插件。
很显然,这两种技术在今天已经被淘汰了。

WebSocket

HTTP升级特性包含了如下一点:
最终我们可以使用任意的协议。
这意味着,在HTTP升级特性 在握手完成后,就可以不再使用HTTP连接,而是使用一个持久的、全双工的TCP Socket连接。
理论上讲这是行得通的,但是浏览器不会让JavaScript开发者随意使用TCP栈,所以就需要指定某些协议,因此就产生了WebSocket协议。

WebSocket连接首先将使用非正常的HTTP请求以特定的模式访问一个URL。URL模式ws和wss分别对应于HTTP的http和https。通过一个Connection:websocket头告诉服务器把连接升级称为WebScoket协议——一个全双工持久的通信协议。

WebScoket协议的实现方式有许多优点:

  • 因为连接在端口80(ws)或者443(wss)上创建,与HTTP使用的端口相同,几乎所有的防火墙都不会阻塞WebSocket连接。
  • 因为它使用HTTP握手,该协议可以集成到网络浏览器和HTTP服务器中。
  • 心跳机制。
  • WebSocket连接关闭时将发送一个特殊的关闭消息,其中可以包含原因代码和用于解释连接被关闭原因的文本。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容