WebSocket 简介和使用
介绍:webSocket 是一种网络通信协议
有了HTTP协议什么还要使用webSocket
因为 HTTP 协议有一个缺陷:通信只能由客户端发起。HTTP 协议做不到服务器主动向客户端推送信息。
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws
(如果加密,则为wss
),服务器网址就是 URL。
简单封装使用
webSocket.js
/**
* 参数:[socketOpen|socketClose|socketMessage|socketError] = func,[socket连接成功时触发|连接关闭|发送消息|连接错误]
* timeout:连接超时时间
* socket.readyState 状态码
* 0 CONNECTING 连接尚未建立
1 OPEN WebSocket的链接已经建立
2 CLOSING 连接正在关闭
3 CLOSED 连接已经关闭或不可用
* @type {module.webSocket}
*/
var isCheckTime;
var failedMaxTimes = 10; //允许重连最大次数
var isSetCheckTime = 4000; //设置延迟避免请求过多
export default class webSocket {
constructor(props) {
this.props = props;
this.socket = null;
this.taskRemindInterval = null;
this.failedTimes= 0; //失败次数
}
connection = () => {
let { socketUrl } = this.props;
// 检测当前浏览器是什么浏览器来决定用什么socket
window.WebSocket = window.WebSocket || window.MozWebSocket;
if (!window.WebSocket) {
// 检测浏览器支持
console.log('Error: WebSocket is not supported .');
return;
}
this.socket = new WebSocket(socketUrl);
this.socket.onopen = this.onopen;
this.socket.onmessage = this.onmessage;
this.socket.onclose = this.onclose;
this.socket.onerror = this.onerror;
this.socket.sendMessage = this.sendMessage;
this.socket.closeSocket = this.closeSocket;
};
reconnect = () => {
console.log( this.socket , '重新连接之前,获取连接状态。。。');
if ( this.socket && this.socket.readyState === 2) {
return;
}
this.socket = null;
var _this = this;
//没连接上会一直重连,设置延迟避免请求过多
isCheckTime && clearTimeout(isCheckTime);
isCheckTime = setTimeout(function () {
_this.connection();
}, isSetCheckTime);
};
// 连接成功触发
onopen = () => {
console.log('连接成功 发送心跳检测')
//心跳检测重置
let { socketOpen } = this.props;
this.failedTimes = 0;
socketOpen && socketOpen();
};
// 后端向前端推得数据
onmessage = msg => {
console.log('onmessage');
let { socketMessage } = this.props;
socketMessage && socketMessage(msg);
};
// 关闭连接触发
onclose = e => {
// clearInterval(this.setIntervalWesocketPush);
console.log('websocket已断开....正在尝试重连onclose', e, this.socket);
this.failedTimes++;
let {timeout } = this.props;
// 根据后端返回的状态码做操作 我的项目是当前页面打开两个或者以上,就把当前以打开的socket关闭 否则就20秒重连一次,直到重连成功为止
if (e.code === '4500') {
this.socket.close();
} else {
if (this.taskRemindInterval) {
clearInterval(this.taskRemindInterval);
}
if (this.failedTimes < failedMaxTimes+1) {
console.warn('connect is failed , try to reconnect, current time:' +this.failedTimes);
this.taskRemindInterval = setInterval(() => {
this.reconnect();
}, 2000);
} else {
console.error('connected timeout , close interval!');
}
}
};
onerror = e => {
// socket连接报错触发
this.reconnect();
};
sendMessage = value => {
console.log('sendMessage');
// 向后端发送数据
if (this.socket) {
this.socket.send(JSON.stringify(value));
}
};
/**
* 发送心跳
*/
sendPing = e => {
let { time } = this.props;
console.log('sendPing...心跳');
this.setIntervalWesocketPush = setInterval(() => {
if (this.socket) {
this.socket.send(JSON.stringify(e));
}
}, time);
};
}
index.js
import Socket from './webSocket';
var userInfo = JSON.parse(localStorage.getItem('userInfo'))?JSON.parse(localStorage.getItem('userInfo')):{};
var todo = process.env.REACT_APP_SOCKET_URL + '/websocket/' + process.env.REACT_APP_EBS + '/todo/' + userInfo.roleId + '/' + userInfo.phone;
var notice = process.env.REACT_APP_SOCKET_URL + '/websocket/' + process.env.REACT_APP_EBS + '/notice/' + userInfo.roleId + '/' + userInfo.phone;
var urls = { todo: todo, notice: notice };
var createSocketObj = {},
timeout = 20000,
time = 20000,
params = { msgType: '!12@+' };
export default function index(opts, callback) {
if (userInfo && userInfo.phone) {
createSocketObj[opts] = new Socket({
socketUrl: urls[opts],
timeout,
time, //心跳时间
socketMessage: receive => {
console.log(receive, opts);
callback(receive);
},
socketOpen: () => {
createSocketObj[opts].sendPing(params);
}
});
createSocketObj[opts].connection();
}
}
页面实例调用
let that = this;
Socket('todo', function (receive) {
console.log(receive, '服务端返回的数据 ------todo');
红色字体是获取服务端数据之后逻辑展示
let todoList = JSON.parse(localStorage.getItem('todoArray')) || [];
todoList.unshift(JSON.parse(receive.data));
localStorage.setItem('todoArray', JSON.stringify(todoList.slice(0, 50)));
that.setState({
todoArray: todoList
});
let itemData = JSON.parse(receive.data);
const key = `open${Date.now()}`;
notification.info({
message: `${itemData.title}`,
duration: 3,
description: (
<div>
<div>
<span>{itemData.content}</span>
</div>
</div>
),
placement: 'bottomRight',
key,
onClick() {
notification.close(key);
}
});
});