最近在做一个实时的项目,其中一个重要的功能就是实时的从后端获取数据。当时就是有两种方案去实现这个功能,一种是浏览器定时向服务器发送请求,服务器接到请求后返回最新的数据(轮询),还有就是使用H5新增的通信协议webSocket。
其实之前有用过轮询的方式做一些东西,它最大的问题就是返回结果的间隔不是我们想要的。比如
setInterval(function() {
$.get("/xxx", function(data, status) {
console.log(data);
});
}, 2000);
上面的程序是每2秒向后台发送一次请求。我们想要的结果是2秒就可以接收一次数据,根据js事件循环机制我们知道,setInterval只是在规定的时间间隔内向任务队列插入了回调函数,但是不会立即执行,这就会导致每次返回结果的时间并不是恰好隔着2秒。
还有一个问题就是浏览器频繁地向服务器发送请求,可能数据并没有更新,这样就造成很多无用的请求,浪费带宽。
websocket的简单介绍
websocket是一个双向通信的协议,连接建立后,服务器和客户端都能主动地向对方发送和接收数据。Websocket使用ws或wss的统一资源标志符,和http、https类似,wss就是对通信进行加密。
1. 握手协议
建立websocket连接,是需要先通过HTTP/1.1协议的101状态码进行握手的。看一下它的握手请求:
websocket.png
其中最重要的就是
Connection: Upgrade
Upgrade: websocket
表示连接升级到websocket协议。
Sec-WebSocket-Version 表示支持的websocket版本
Sec-WebSocket-Key 主要用来生成响应头中Sec-WebSocket-Accept的值
2、优点
对于websocket的优点,我们看一下维基百科里面的介绍(websocket):
- 较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较少。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节;对于客户端到服务器的内容,此头部还需要加上额外的4字节的掩码。相对于HTTP请求每次都要携带完整的头部,此项开销显著减少了。
- 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少
- 保持连接状态。与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。
- 更好的二进制支持。
- 可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等
- 更好的压缩效果。相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。
使用
const ws = new WebSocket(`ws://example.com/newEnergyWebSocket`);
ws.onopen = (evt) => { // 连接成功后的回调函数
console.log('Connection open ...', ws.readyState);
if (ws.readyState === 1) {
ws.send(1); // 向服务器发送数据,可以在这里传递接口参数
}
};
ws.onmessage = (evt) => { // 收到数据后的回调函数
console.log('Received Message: ');
// 接收数据
};
ws.onclose = (evt) => { // 连接关闭后的回调函数
console.log('Connection closed.');
};
webSocket.readyState返回当前实例的连接状态:
- CONNECTING:值为0,表示正在连接。
- OPEN:值为1,表示连接成功,可以通信了。
- CLOSING:值为2,表示连接正在关闭。
-
CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
连接建立后就可以接收数据了:
websocket2.png
要想关闭连接调用close方法:
ws.close()
后端用的公司的框架,一开始因为tomcat版本太低一直报错:
websocket1.png
后来升级到7.0.7之后就好了。
网友评论