一,认识websocket
HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。 WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。WebSocket是一个持久化的协议,这是相对于http非持久化来说的。
对大部分web前端开发者来说,其实只要记住几点:
- WebSocket可以在浏览器里使用
- 支持双向通信
- 使用很简单
1,有哪些优点
这里的对比参照物是HTTP协议,概括地说就是:支持双向通信,更灵活,更高效,可扩展性更好。
- 支持双向通信,实时性更强。
- 更好的二进制支持。
- 较少的控制开销。连接创建后,ws客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有2~10字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。
- 支持扩展。ws协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)
- 协议标识符是
ws(如果加密,则为wss),服务器网址就是 URL。
2,需要学习些什么
最重要的往往就是连接建立过程、数据交换教程。当然,数据的格式是逃不掉的,因为它直接决定了协议本身的能力。好的数据格式能让协议更高效、扩展性更好。
下面是参考图:
二,如何使用Websocket
对于web前端开发者来说,使用websocket其实还是很简单的,因为websocket本身就是广播-收听 模式(也有人称为发布-订阅模式),对此,前端开发者只需要进行建立连接-监听动作-操作动作这几个步骤,就能体验一系列websocket的流程
1,建立连接
var ws = new WebSocket("ws://你的域名或ip");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
WebSocket 对象作为一个构造函数,用于新建 WebSocket 实例。 执行上面代码后,客户端就会与服务器进行连接。 我们会得到一个ws实例,其中实例中有许多属性,这里只挑平时经常使用的来讲
2, ws.readyState属性返回实例对象的当前状态,共有四种。
CONNECTING:值为0,表示正在连接。
OPEN:值为1,表示连接成功,可以通信了。
CLOSING:值为2,表示连接正在关闭。
CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
我们可以通过监听ws.readyState去判断socket的连接状态。
3, ws.onopen 实例对象的onopen属性,用于指定连接成功后的回调函数。
如连接成功后回调函数
```js
ws.onopen = function () {
ws.send('Hello Server!');
}
```
4, ws.onclose 实例对象的.onclose属性,用于连接关闭后的回调函数。
ws.onclose = function(event) {
// handle close event 用于连接关闭后,用户端需要执行的某些操作
};
5, ws.onmessage 实例对象的.onmessage属性,用于收到服务器返回数据后的回调函数。
ws.onmessage = function(event) {
var data = event.data;
// 处理数据
};
6, ws.send 方法用于向服务器发送数据。
发送的格式具体需要跟后端协商定义,比如发送普通文本:
ws.send('your message');
7, ws.onerror 用于连接报错时的回调函数。
一般连接报错,我们只需要执行重新连接就好了。
ws.onerror = function(event) {
// handle error event
};
三,在对接websocket时遇到的问题
-
基于网络安全协议的条件,https不同源情况下连接socket需要使用wss://+域名 方式,后端必须使用端口443(并且不启动任何其他安全端口)还需要侦听反向代理并将所有wss流量传递到目标websocket服务器
-
wss连接socket 服务器会避免资源浪费,在长时间(或nginx设定的超时时间)无操作情况下,socket会执行断开连接,需要我们做心跳检测操作,定时向后端发送心跳包
例子:
var heartCheck = { timer: 0, _obj : null, _callback:null, init: function(wsObj, callback) { console.log("init"); this._obj = wsObj; callback && (this._callback = callback); this.sayHi(); }, sayHi: function() { clearTimeout(this.timer); this.timer = setTimeout(() => { this.onError(); }, 10000); //连接成功,发送一个心跳包,并开启一个延时器,如果超过延时器设定的值未响应,执行onError方法 this._obj.send("hi," + this.timer); console.log("sayHi:" + this.timer); }, clear: function(flag) { //清除上一次的延时器,重新发送心跳包,如果flag传入为true 则断开 console.log("clear:" + this.timer); clearTimeout(this.timer); if(true === flag){ console.log("heartCheck finished"); return; } setTimeout(()=>{ this.sayHi(); }, 3000); }, onError: function() { console.log("onError:",this.timer); clearTimeout(this.timer); this._callback && this._callback(); } }; //let hc = new heartCheck(); let uri = "ws://localhost:8080"; var ws = new WebSocket(uri); ws.onopen = (event) => { console.log('ws onopen', event); ws.send('from client: hello'); heartCheck.init(ws); }; ws.onmessage = (event) => { console.log('ws onmessage'); console.log('from server: ', event); showLog(event.data); heartCheck.clear(); }; ws.onclose = (event) => { console.log("ws close", event); console.log(ws); heartCheck.clear(true); }; ws.onerror = (event) => { console.log("ws error", event); console.log(ws); }; -
https不能请求http
https地址中,如果加载了http资源,浏览器将认为这是不安全的资源,将会默认阻止,这就会给你带来资源不全的问题了,比如:图片显示不了,样式加载不了,JS加载不了。 因为样式类,基本上都是写在本地的,所以一般还可以,但是一些公共的js文件,往往就是存在于cdn或者其他服务器上,这时候,如果访问不了,可能就导致了业务就完全操作不了。比如:jquery效法加载失败,可能所有的操作、请求都将无效了。