ShiningDan的博客

前端的那些(比较)新协议

由于现在前端业务的飞速发展,与之相关的前端协议也在不断出现,为前端的进步提供更多的可能性。在本文中,总结了一下常用的比较新的前端协议,其实有的协议其实也有些年头了,但是大家可能接触的也不是很多,通过本文,希望给大家带来一些大体上的认知。

WebRTC

WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。

关于 WebRTC 相关的介绍,可以参考文章 WebRTC API | MDN,这里介绍了 WebRTC 的低层协议、架构、API 概述等。

WebRTC实现了三个API,分别是:

  • MediaStream:通过MediaStream的API能够通过设备的摄像头及话筒获得视频、音频的同步流
  • RTCPeerConnection:RTCPeerConnection是WebRTC用于构建点对点之间稳定、高效的流传输的组件,这个音频和视频数据通道,通信是点对点的,不需要经过服务器进行中转。但是这并不意味着我们能抛弃服务器,在通道建立之前,我们需要服务器传递信令(signaling)来建立这个信道。
  • RTCDataChannel:RTCDataChannel使得浏览器之间(点对点)建立一个高吞吐量、低延时的信道,用于传输任意数据

WebSocket

HTTP 协议有一个缺陷:通信只能由客户端发起。

对于那些实时要求比较高的应用来说,比如说在线游戏、在线证券、设备监控、新闻在线播报、RSS 订阅推送等等,当客户端浏览器准备呈现这些信息的时候,这些信息在服务器端可能已经过时了。所以保持客户端和服务器端的信息同步是实时 Web 应用的关键要素,对 Web 开发人员来说也是一个难题。在 WebSocket 规范出来之前,开发人员想实现这些实时的 Web 应用,不得不采用一些折衷的方案,其中最常用的就是轮询 (Polling) 和 Comet 技术,而 Comet 技术实际上是轮询技术的改进,又可细分为两种实现方式,一种是长轮询机制,一种称为流技术。下面我们简单介绍一下这几种技术:

轮询

这是最早的一种实现实时 Web 应用的方案。客户端以一定的时间间隔向服务端发出请求,以频繁请求的方式来保持客户端和服务器端的同步。

Comet

而 Comet 技术实际上是轮询技术的改进,又可细分为两种实现方式,一种是长轮询机制,一种称为流技术。

长轮询

长轮询把短轮询颠倒了一下,页面发起一个到服务器的请求,然后服务器一致保持连接打开,直到有数据可以发送。发送完数据后,浏览器关闭连接,随即又发起一个到服务器的新请求,这一过程呢在页面打开期间一直持续不断。当然,如果服务端的数据变更非常频繁的话,这种机制和定时轮询比较起来没有本质上的性能的提高。

HTTP 流

流技术方案通常就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服务器端的连接不过期。

HTTP 流在整个生命周期内只使用一个 HTTP 连接,就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。

但是管理 Comet 是很容易出错的,所以为了简化这一技术,又为 Comet 创建了两个新的接口。

Server-Sent Events (SSE)

服务器发送事件,是围绕只读 Comet 交互推出的 API 或者模式。SSE API 用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。服务器响应的 MIME 类型必须是 text/event-stream。

使用方法是创建一个 EventSource 对象,然后主要配置 open、message、error 这三个事件的处理程序。

1
2
3
4
5
let source = new EventSource("myevents.php");
source.onmessage = function(event) {
let data = event.data;
// 处理数据
}

默认情况下,EventSource 对象会保持与服务器的活动连接,如果连接断开,还会重新连接。这意味着 SSE 适合长轮询和 HTTP 流。如果想强制立即断开连接并且不再重新连接,可以调用 source.close()

除此以外,还可以给特定事件添加一个 id,如果连接断开,EventSource 对象会跟踪上一次触发的事件,从而向服务器发送该 id,让服务器知道下一次该触发哪个事件。

WebSocket

HTML5 WebSocket 设计出来的目的就是要取代轮询和 Comet 技术,使客户端浏览器具备像 C/S 架构下桌面系统的实时通讯能力。 浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。因为 WebSocket 连接本质上就是一个 TCP 连接,所以在数据传输的稳定性和数据传输量的大小方面,和轮询以及 Comet 技术比较,具有很大的性能优势。

WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息Upgrade: WebSocket 表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
客户端到服务端: 
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Upgrade: WebSocket
Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5
Origin: http://example.com
[8-byte security key]

服务端到客户端:
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket-Origin: http://example.com
WebSocket-Location: ws://example.com/demo
[16-byte hash response]

建立 WebSocket 连接的实例 JavaScript 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var wsServer = 'ws://localhost:8888/Demo'; 
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) { onOpen(evt) };
websocket.onclose = function (evt) { onClose(evt) };
websocket.onmessage = function (evt) { onMessage(evt) };
websocket.onerror = function (evt) { onError(evt) };
function onOpen(evt) {
console.log("Connected to WebSocket server.");
}
function onClose(evt) {
console.log("Disconnected");
}
function onMessage(evt) {
console.log('Retrieved data from server: ' + evt.data);
}
function onError(evt) {
console.log('Error occured: ' + evt.data);
}

注意,WebSocket 只能发送文本数据,对于复杂的数据结构,在通过连接发送之前,必须进行序列化

接收到服务器的数据,可以是文本数据,也可能是 Blob 对象或者 ArrayBuffer 对象

Blob对象表示不可变的类似文件对象的原始数据。ArrayBuffer对象被用来表示一个通用的,固定长度的二进制数据缓冲区。具体差别可以查看这篇文章:理解DOMString、Document、FormData、Blob、File、ArrayBuffer数据类型

SPDY

在2010年到2015年,谷歌通过实践了一个实验性的SPDY协议,证明了一个在客户端和服务器端交换数据的另类方式。其收集了浏览器和服务器端的开发者的焦点问题。明确了响应数量的增加和解决复杂的数据传输,SPDY成为了HTTP/2协议的基础。

SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。

SPDY(会话层)的设计特点是在SSL层(表示层)的基础上,增加了一个会话层,从而在一个tcp 连接基础上,实现了多并发和交叉流传输。HTTP 的GET ,POST 仍旧采用旧有的消息格式,当然SPDY 协议对原有的数据做了封装和编码

SPDY的特性

流复用

是允许在一个TCP连接里面,允许无限并发流

优先级

因为支持并行,所以必须要有优先级机制

SPDY实现请求的优先次序:客户端可以请求尽可能多的项目,每个请求分配一个优先级。这样 即使高优先级的请求仍处在pending状态,通道也不会传输非关键的,低优先级的请求,这样就有效地阻止了传输拥塞。

Http header压缩

对于HTTP 请求,响应头,SPDY都做了 gzip 压缩

服务器端推送

SPDY通过X-Associated-Content 协议头来向客户端推送数据。通知客户端,我要向你推送资源,准备接收好了。

Server hint

不像上面提到的PUSH 技术,服务器会先告诉浏览器,你可以下载ABC资源了,这个ABC资源,可能就是下一个页面的JS ,CSS ,或者内容。服务器不会主动推送的,仍旧等待客户端请求,这对于低速网络,是个很大的优化,有点类似于我们的预加载技术。

安全防攻击

SPDY采用了SSL+数据压缩,安全性上有了很大提升。

工作机制

SPDY会话层会把请求封装成一个SPDY frame(SPDY帧),然后把SPDY帧丢给ssl层或者tcp层发送

HTTP1.0/1.1/2

HTTP,HTTP2.0,SPDY,HTTPS你应该知道的一些事 这篇文章中可以了解一些。

HTTP1.0和HTTP1.1的一些区别

主要区别主要体现在:

  1. 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
  2. Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)
  3. 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive

HTTPS与HTTP的一些区别

  1. HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。
  2. HTTP协议运行在TCP之上,所有传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。
  3. HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  4. HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。

HTTP 2.0

HTTP2.0可以说是SPDY的升级版(其实原本也是基于SPDY设计的),但是,HTTP2.0 跟 SPDY 仍有不同的地方,主要是以下两点:

  1. HTTP2.0 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPS
  2. HTTP2.0 消息头的压缩算法采用 HPACK,而非 SPDY 采用的 DEFLATE

HTTP2.0的新特性:

  1. 新的二进制格式
  2. 多路复用(MultiPlexing):在应用层(HTTP/2)和传输层(TCP or UDP)之间增加一个二进制分帧层,HTTP/2 会将所有传输的信息分割为更小的消息和帧(frame),并对它们采用二进制格式的编码,HTTP/2 通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。
  3. header压缩:HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
  4. 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能

参考