为什么需要Web Socket
假设我们使用过http,应该清楚它是客户端和服务端『快问快答』的过程。比如使我用『http』进入咖啡店可能是这样的情景。
我:你好,最近有什么新品吗?
店员:没有~
我:那有什么优惠活动吗?
店员:美式第二杯半价哦~
我:那我要两杯美式吧
店员:好的,稍等~
接下来有趣的事情发生了。
我:你好,我的咖啡好了吗?
店员:还没有~
a few moments later......
我:咖啡好了吗?
店员:好了,您拿好~
在反复地询问中,店员应该很想抱怨顾客的啰嗦吧(但是http的服务端不能主动抱怨);顾客应该在过程中不耐烦了吧(客户端还有其他的事情要忙)。
生活中我们也不是这样做的。我们会基于常识调整『轮询』的间隙,如果对于咖啡的认知是6分钟,我们可能会在4-8分钟加快『轮询』的频率。而且我们也会东张西望,发现晚于自己下单的某人取到餐了,开始询问。可惜的是,客户端之前一般不能张望。
那么如果用Web Socket会怎样。
我:那我要两杯美式吧
店员:好的,你的单号是A01,稍后叫号取餐~
a few moments later......
店员:A01号顾客取餐~
我:好的
体验提升了一些,店员在下单到交付过程中可以主动和顾客说话了;顾客在过程中也有一定的自由度,体现在不必反复去询问、只要呆在听得见叫号的地方忙些其他事情也可以。
如果说http是快问快答,那Web Socket就是和客服打电话。特点如下:
- 需由客户端发起,建立连接为http握手过程。
- 通信基础为,双方都保持链接。
- 过程为全双工,双方都可主动通信。
- 通信过程不宜太长,服务端保持链接占用资源(内存记录通信上下文、服务器并发量)。
如何使用Web Socket
因为是全双工的协议,客户端和服务端的行为大致对称。* 以下服务端为node.js,自行载入ws npm包。 *
浏览器
// 建立连接
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = function (err) {
// 连接建成
};
ws.onmessage = function (data) {
// 收到信息
};
ws.onerror = function (err) {
// 连接报错
};
ws.onclose = function (reason) {
// 连接断开
}
// 发送消息
ws.send('to server');
// 关闭连接
ws.close();
服务端
const WebSocket = require('ws');
// 监听连接
const websocket = new WebSocket.Server({ port: 8080 });
websocket.on('connection', ws => {
// 连接建成
ws.on('message', data => {
// 收到信息
});
ws.on('error', err => {
// 连接报错
});
ws.on('end', ws => {
// 连接断开
});
// 发送消息
ws.send('to client');
// 关闭连接
ws.close();
});
疑问
** 异常处理: **一次http请求可以通过状态码判断请求成功与否,但是在Web Socket中send方法的异常是异步抛出的,不知道如何通过js程序捕获?error事件可以监听报错,但是无法为每个信息定位?
switch (ws.readyState) {
case ws.OPEN :
ws.send('to server');
break;
case ws.CONNECTING :
console.log('CONNECTING');
break;
case ws.CLOSING :
console.log('CLOSING');
break;
case ws.CLOSED :
console.log('CLOSED');
break;
}
这样的预检查可以解决一部分问题,相当于打电话『喂,在听吗』『嗯,我在』。但是后面的通话异常还是不能被说话人得知。就像『不好意思,我没听清』,我们是通过电流声、前后语义连贯性做出的判断,如果是一整段话的缺失,我们也无法察觉。但是,Web Socket不管连贯性的,通信过程的异常处理是如何保证的呢,望大佬指点![抱拳] [抱拳] [抱拳]