# 网络请求-WebSocket

WebSocket 协议提供了一种在浏览器和服务器之间建立持久连接来交换数据的方法。

数据可以作为“数据包”在两个方向上传递,而不会断开连接和其他 HTTP 请求。

对于需要连续数据交换的服务,例如网络游戏,实时交易系统等,WebSocket 尤其有用。

# 一个简单例子

要打开一个 WebSocket 连接,我们需要在 url 中使用特殊的协议 ws 创建 new WebSocket:

let socket = new WebSocket("ws://javascript.info");

同样也有一个加密的 wss:// 协议。类似于 WebSocket 中的 HTTPS。

一旦 socket 被建立,我们就应该监听 socket 上的事件。一共有 4 个事件:

  • open —— 连接已建立,
  • message —— 接收到数据,
  • error —— WebSocket 错误,
  • close —— 连接已关闭。 ……如果我们想发送一些东西,那么可以使用 socket.send(data)

# 建立 WebSocket

当 new WebSocket(url) 被创建后,它将立即开始连接。

在连接期间,浏览器(使用 header)问服务器:“你支持 WebSocket 吗?”如果服务器回复说“我支持”,那么通信就以 WebSocket 协议继续进行。

new WebSocket("wss://javascript.info/chat") 发出的请求的浏览器 header 示例

GET /chat
Connection: Upgrade  
Upgrade: websocket
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13

如果服务器同意切换为 WebSocket 协议,服务器应该返回响应码 101:

101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=

# 数据传输

WebSocket .send() 方法可以发送文本或二进制数据。

socket.send(body) 调用允许 body 是字符串或二进制格式,包括 Blob,ArrayBuffer 等。不需要额外的设置:直接发送它们就可以了。

而当我们收到数据时,文本总是以字符串形式呈现。而对于二进制数据,我们可以在 Blob 和 ArrayBuffer 格式之间进行选择。

它是由 socket.binaryType 属性设置的,默认为 "blob",因此二进制数据通常以 Blob 对象呈现。

但是对于二进制处理,要访问单个数据字节,我们可以将其改为 "arraybuffer"

socket.binaryType = "arraybuffer";
socket.onmessage = (event) => {
  // event.data 可以是文本(如果是文本),也可以是 arraybuffer(如果是二进制数据)
};

# 关闭连接

通常,当一方想要关闭连接时(浏览器和服务器都具有相同的权限),它们会发送一个带有数字码(numeric code)和文本形式的原因的 “connection close frame”。

它的方法是:

socket.close([code], [reason]);

# 总结

WebSocket 是一种在浏览器和服务器之间建立持久连接的现代方式。

  • WebSocket 没有跨源限制。
  • 浏览器对 WebSocket 支持很好。
  • 可以发送/接收字符串和二进制数据。

WebSocket 的 API 很简单。

WebSocket 方法:

  • socket.send(data)
  • socket.close([code], [reason])

WebSocket 事件:

  • open
  • message
  • error
  • close