4

SPDY

谷歌于 2012 年提出 SPDY(取自 SPeeDY,发音同 speedy) ,其开发目标旨在解决 HTTP 的性能瓶颈,缩短 Web 页面的加载时间 ,属于增强 HTTP 协议。SPDY 一直处于草案阶段,现在已经被 HTTP/2.0 取代,Chrome 51 已经移除对 SPDY 的支持。

结构设计

SPDY 官方定义为会话层协议(OSI 模型),在 TCP/IP 模型中可以归类为应用层,介于 TLS/SSL 与 HTTP 之间。类似于前面讲过的 HTTPS 设计(传送门),不会改变现有的 HTTP 的实现,对于实际应用几乎透明。

示意图:
SPDY

OSI 将计算机网络体系结构划分为七层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
其中会话层的作用:允许用户使用简单易记的名称建立连接 相当于公司中收寄信、写信封与拆信封的秘书。

SPDY 为 HTTP 提供的改进

多路复用

通过单一的 TCP 连接,可以无限制处理多个 HTTP 请求。所有请求的处理都在一条 TCP 连接上完成,因此 TCP 的处理效率得到提高。

赋予请求优先级

SPDY 不仅可以无限制地并发处理请求,还可以给请求逐个分配优先级顺序。这样主要是为了在发送多个请求时,解决因带宽低而导致响应变慢的问题。

压缩 HTTP 报文头

解决了 HTTP 只能压缩报文体,不能压缩报文头的问题。通信产生的数据包数量和发送的字节数就更少了。

推送功能

支持服务器主动向客户端推送数据的功能。服务器可直接发送数据,而不必等待客户端的请求,打破了 HTTP 协议的客户/服务器模式。

服务器提示功能

服务器可以主动提示客户端请求所需的资源。由于在客户端发现资源之前就可以获知资源的存在,因此在资源已缓存等情况下,可以避免发送不必要的请求。

强制使用 HTTPS

为了更加安全,SPDY 强制要求建立 STL/SSL 连接。

WebSocket 协议

WebSocket,即 Web 浏览器与 Web 服务器之间全双工通信标准。其中,WebSocket 协议由 IETF 定为标准,WebSocket API 由 W3C 定为标准。作为基于 HTTP 的补充协议,可以实现双工通信,完全打破 HTTP 客户/服务器模式,如果把 Ajax 比做发电报,那 WebSocket 就好比打电话。

结构设计

WebSocket 是基于 HTTP 的渐进式升级,它依赖 HTTP 完成“握手”,如果一方不支持该协议,则可以由开发者选择降级方案。由于是建立在 HTTP 基础上的协议,因此连接的发起方仍是客户端,而一旦确立 WebSocket 通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文。

WebSocket的“握手”

客户端请求

请求报文头里新增:

Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: <随机加密串>
Sec-WebSocket-Protocol: <自定义服务名>
Sec-WebSocket-Version: <协议版本号>

服务器应答

状态码:101 Switching Protocols
响应报文头里新增:

Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: <加密key>
Sec-WebSocket-Protocol: <自定义服务名>

示意图:
WebSocket 握手

WebSocket 为 HTTP 提供的改进

推送功能

这是全双工通信带来的结果之一,支持由服务器向客户端推送数据的推送功能,也就是说服务器可以在客户端未请求的情况下,主动发送数据给客户端。这种需求在即时通讯等场景很常见。

减少通信量

理论上 WebSocket 就是为了长连接设计的,一旦建立连接就不会断开,也就是说不需要频繁“握手”。和 HTTP 相比,不但每次连接时的总开销减少,而且由于 WebSocket 的首部信息很小,通信量也相应减少了。

降级方案

Ajax 轮询和Ajax 长轮询(Long Poll),详见进阶篇的连接管理模型(传送门)。

实践示例

nodejs 可以使用 nodejs-websocket 包实现 WebSocket 服务。现代的浏览器均可以支持 WebSocket 的 API。
下面代码可以在本地演示了客户端报单数,服务器报双数的循环交互。

// 服务器,会监听8001端口。

const ws = require('nodejs-websocket')
const port = 8001
const server = ws.createServer(function (conn) {
    conn.on('text', function (str) {
        // 接收客户端的消息
        console.log('client:' + str)
        if (str === 'what`s your name?') {
        // 应答问候语
        conn.sendText('My name is webSocket server!')
        } else {
        // 累加数字
        conn.sendText(JSON.stringify(Number(str) + 1))
    }
    })
    conn.on('close', function (code, reason) {
        console.log('webSocket close')
    })
    conn.on('error', function (code, reason) {
        console.log('webSocket error')
    })
})
.listen(port)
console.log(`webSocket listen on ${port} successfully`)
// 客户端,将这代码引入一个html文件,用浏览器打开html即可。

if (!window.WebSocket) {
    console.error('browser does not support WebSocket')
    return
}
const ws = new WebSocket('ws://localhost:8001')
let count = 0
ws.onopen = function (e) {
    console.log('connection success')
    // 问候语
    ws.send('what`s your name?')
    ws.send(count)
}
ws.onclose = function (e) {
    console.warn('connection close')
}
ws.onerror = function () {
    console.error('connection error')
}
// 接收服务器的消息
ws.onmessage = function (e) {
    let message = 'server:' + e.data + ''
    console.log(message)
    if (e.data !== 'My name is webSocket server!') {
        // 累加数字
        setTimeout(() => {
            ws.send(Number(e.data) + 1)
        }, 1000)
    }
}

WebDAV

WebDAV(Web-based Distributed Authoring and Versioning),即基于万维网的分布式创作和版本控制。是一个可对 Web 服务器上的内容直接进行文件复制、编辑等操作的分布式文件系统。它作为扩展 HTTP/1.1 的协议定义在 RFC4918。但因为对实时性和安全性的问题,实际上很少用,虽然类似于当今的流行的网盘,但他们本质是不同的。

结构设计

WebDAV 的实现是对 HTTP/1.1 的扩展,在原有的请求方法和状态码的基础上,针对服务器上的资源,新增加了一些概念。

  • 集合(Collection):是一种统一管理多个资源的概念。以集合为单位可进行各种操作。也可实现类似集合的集合这样的叠加。
  • 资源(Resource):把文件或集合称为资源。
  • 属性(Property):定义资源的属性。定义以“名称 = 值”的格式执行。
  • 锁(Lock):把文件设置成无法编辑状态。多人同时编辑时,可防止在同一时间进行内容写入。

追加的请求方法

方法用途
PROPFIND获取属性
PROPPATCH修改属性
MKCOL创建集合
COPY复制资源及属性
MOVE移动资源
LOCK资源加锁
UNLOCK资源解锁

新增状态码

状态码含义
102 Processing可正常处理请求,但目前是处理中状态
207 Multi-Status存在多种状态
422 UnprocessibleEntity格式正常,内容有误
423 Locked资源已被加锁
424 FailedDependency处理与某请求关联的请求失败,因此不再维持依赖关系
507 InsufficientStorage保存空间不足

HTTP/2.0

概述

HTTP/2.0 是 HTTP 协议自 1999 年 HTTP/1.1 发布后的首个更新,主要基于 SPDY 协议。
HTTP/2.0 基本上都能解决上面提到的有关 HTTP/1.0 遇到的瓶颈。

分层结构

HTTP/2.0 在原有的 HTTP 层前加入了分帧层,类似与 SPDY 协议的结构,分帧层介于 STL/SSL 与 HTTP 之间。

  • 分帧层:HTTP/2.0 特性的核心部分;
  • 数据/HTTP层:其中包含传统上被认为是 HTTP 及其关联数据的部分。

结构如图:(图片来自网络)
分层结构.png

特点:

  • 二进制分帧
    HTTP/2.0 的分帧层是基于帧的二进制协议,最小消息单位是帧。这方便了机器解析,解析更加高效。每个数据流都以消息的形式发送,而消息由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。
  • 首部压缩
    H2 在客户端和服务端使用“首部表”来跟踪和存储之前发送的头部键值对,每次只需要差量更新,不需要重复交换;
    首部表在 H2 的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
    头部内容也会被压缩处理。
  • 多路复用
    基于二进制分帧的特性,所有请求通过一个 TCP 连接并发完成,不在依赖多开 TCP 连接去实现并行加载。
  • 并行双向字节流的请求和响应
    基于二进制分帧的特性,同一个 TCP 连接上同时有多个不同方向的数据流,因此客户端可以一边乱序发送,一边接收响应,服务器也如此。
  • 加密传输
    虽然协议并未严格限制,但现代浏览器都要求必须使用 HTTPS,已成为了事实上的强制标准。
  • 服务器推送
    服务器可以主动将 HTML 页面相关的 js 和 css 文件推送给浏览器,不需要等待浏览器解析 HTML 后再发起请求获取。遵循同源策略,浏览器可拒绝。
  • 请求优先级
    基于二进制分帧的特性,请求可以带上 32bit 的优先级值,0 表示最高优先级,数值越大优先级越低,可以制定策略优化传输。

存在的问题

HTTP/2.0 虽然已经解决了 HTTP/1.0 的诸多瓶颈问题,但依然存在问题,这些问题基本都是由于TCP协议本身的限制导致的。

  • 队头阻塞:这是 TCP 协议本身可靠性的重传机制导致的问题,如果出现丢包,那就会不断重试。这时候又只有一条 TCP 连接,所以会导致性能还不如 HTTP1.1。
  • 握手延迟大:TCP 协议的三次握手依然无法避免。

QUIC

概述

QUIC 是 Quick UDP Internet Connections的缩写,读作 quick。由 Google 开发。
可以认为 QUIC 是为了解决 HTTP/2.0 在 TCP 遇到的瓶颈,而在 UDP 上做探索所设计的方案。(参考上面 HTTP2 的存在问题)

特性

  • 没有队头阻塞的多路复用。
  • UDP 协议依据 id 寻找目标设备,在多变的移动网络有优势。
  • 前向纠错,每个包还包括其他包的部分信息,可以在丢包的情况下依靠已接受的包的冗余数据拼凑出丢失的部分,减少重传。
  • 不需要多次握手,降低延迟。

calimanco
1.4k 声望766 粉丝

老朽对真理的追求从北爱尔兰到契丹无人不知无人不晓。