如何使用WebSocket
基本概念
概述
WebSocket是一种在单个TCP连接上进行全双工通信的协议。
旨在解决Web应用程序 客户端 与 服务端 之间若要进行双向通信不得不使用轮询这种开销极大的方式的问题。
特点
- 全双工 服务端可以主动向客户端推送信息,客户端也可以主动向服务端发送信息
- 与HTTP共享端口,基于HTTP完成握手
- 数据传输基于帧,支持发送文本类型数据和二进制数据
- 没有同源限制,客户端可以与任意服务端通信
- 支持协议标识(ws或wss)与寻址,通过URL指定服务
握手
WebSocket握手基于HTTP,只需一次握手即可完成连接,具体握手流程如下:
客户端发起握手
通过HTTP请求告知服务端需要更换通信协议
GET ws://localhost:3000/hello HTTP/1.1
Host: 192.168.0.110:8080
Connection: Upgrade
Upgrade: websocket
Origin: http://localhost:8080
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: ddWE76tEFVgUfKjHIWDWvw==
- 请求必须是有效的HTTP请求
- 请求的方法必须是GET,HTTP版本至少是1.1。
- 请求的URL必须满足以下格式要求 ws:// {host} [ : {port} ] {path} [ ? {query} ]或wss:// {host} [ : {port} ] {path} [ ? {query} ]
- 请求首部必须包含Origin字段
- 请求首部必须包含Upgrade字段,且值为websocket,由于Upgrade字段只在客户端和邻接服务端产生作用,所以也必须包含Connection字段,且值为Upgrade,代理会在转发前删除Upgrade字段和Connection字段,然后再进行转发。
- 请求首部必须包含Sec-WebSocket-Version字段,值为13,用于指定协议版本
- 请求首部必须包含Sec-WebSocket-Key字段,值必须为一个16位的base64编码的字符串
服务端接收握手
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 2EoQihfR9RZchLRSwVgDycMsrOE=
Origin: http://localhost:8080
对请求头中的信息进行验证,若验证通过则返回状态码为101的响应,在此只对Sec-WebSocket-Key字段的验证过程进行简单描述,如下:
- 服务端将请求头中Sec-WebSocket-Key字段的值拿出来与GUID进行拼接
- 将拼接后的值使用SHA-1进行计算出摘要
- 使用base64对摘要进行编码
- 将编码值设置为响应头字段Sec-WebSocket-Accept的值,返回至客户端
- 客户端使用同样的流程,并将最终的结果与服务端返回的值进行比对,若相等,则验证通过
算法的简单Node.js实现如下:
安装依赖
yarn add js-sha1
const requestSecWebSocketKey = "ddWE76tEFVgUfKjHIWDWvw==";
const guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
const sha1 = require("js-sha1");
var hash = sha1.create();
hash.update(requestSecWebSocketKey);
hash.update(guid);
const result = Buffer.from(hash.digest(), "utf-8").toString("base64");
console.log(result);// 2EoQihfR9RZchLRSwVgDycMsrOE=
具体的验证规则请查阅RFC6455
应用
使用Node.js搭建简单的WebSocket服务端
安装依赖