1_websocket工具封装
Websocket
前言
-
为什么需要 WebSocket?
- http协议通信只能由客户端发起。若服务器有连续的状态变化,客户端需要通过“轮询”才可获知
轮询的效率低,非常浪费资源(需要不停连接,或者http连接始终打开)
-
WebSocket 最大的特点:服务器可以主动向客户端推送消息,客户端也可以主动向服务器发送消息,是双向平等对话,属于服务器推送技术的一种。
-
WebSocket 其它特点
-
建立在TCP协议之上,服务端的实现比较容易
-
与http协议有着良好的兼容性。默认端口是80和443,并且握手阶段采用http协议
-
数据格式比较轻量,性能开销小,通信高效
-
可以发送文本,也可以发送二进制数据
-
没有同源限制,客户端可以与任意服务器通信
-
协议标识符是ws,服务器网址就是url
ws://example.com:80/some/path
-
1 构造函数
-
new WebSocket(url[, protocols])
-
参数
url
:要连接到的 URLprotocols
:单个协议字符串或协议字符串数组
2 实例属性
-
binaryType
:接收的二进制数据的类型blob
arraybuffer
-
readyState
:websocket 连接的当前状态
readyState 值 | mean | 解释 |
---|---|---|
0 | connecting | 已创建 socket,连接尚未打开 |
1 | open | 连接打开且已做好通信准备 |
2 | closing | 连接正在关闭 |
3 | closed | 连接已关闭 |
3 实例方法
-
close()
:关闭连接-
close(code, reason)
-
参数
code
:指示关闭原因- 1000:正常关闭
- 1001-1015:指示实际原因
-
-
send(data)
:发送数据
4 事件
-
close
:websocket 连接关闭时触发 close 事件-
addEventListener("close", (event) => {});
-
onclose = (event) => {};
-
属性
code
:服务器发送的关闭代码reason
:服务器关闭连接的原因wasClean
:是否已完全关闭
-
-
error
:与 websocket 连接由于错误而关闭时触发 error 事件addEventListener("error", (event) => {});
onerror = (event) => {};
-
message
:websocket 接收到数据时触发 message 事件-
addEventListener("message", (event) => {});
-
onmessage = (event) => {};
-
属性
data
origin
:消息来源
-
-
open
:与 websocket 建立连接时触发 open 事件addEventListener("open", (event) => {});
onopen = (event) => {};
import { useState, useRef, useEffect } from 'react';
interface WebSocketOptions {
url: string;
onOpen?: () => void;
onMessage?: (message: any) => void;
onClose?: (event: Event) => void;
onError?: (event: Event) => void;
reconnectInterval?: number;
reconnectAttrmpts?: number;
}
const defaultOptions: Required<WebSocketOptions> = {
url: '', // 连接的长连接
onOpen: () => {}, // 开启连接
onMessage: () => {}, // 消息
onClose: () => {}, // 关闭连接
onError: () => {}, // 异常
reconnectInterval: 1000, // 重连时长设置
reconnectAttrmpts: Number.MAX_VALUE // 最大连接范围数
};
const useWebsocket = (options: WebSocketOptions): [WebSocket | undefined, (message: any) => void, string, boolean] => {
const { url, onOpen, onClose, onMessage, onError, reconnectInterval, reconnectAttrmpts } = {
...defaultOptions,
...options
};
const [isConnected, setIsConnected] = useState(false); // 是否连接
const [reconnectCount, setReconnectCount] = useState(0); // 是否重连
const [newMessage, setNewMessage] = useState(''); // 最新消息
const wsRef = useRef<WebSocket>();
const reconnectTimerRef = useRef<NodeJS.Timer>();
const connect = () => {
setIsConnected(false);
const ws = new WebSocket(url);
// 与 websocket 建立连接时触发
ws.onopen = () => {
console.log('----------websocket is connected---------');
setIsConnected(true);
setReconnectCount(0);
onOpen();
};
// websocket 接收到数据时触发
ws.onmessage = event => {
const message: any = JSON.parse(event.data);
console.log(`----------websocket reveived message: ${message}--------------`);
setNewMessage(event.data);
onMessage(message);
};
// websocket 连接关闭时触发
ws.onclose = event => {
console.error(`-----------wesocket closed with code ${event.code}-----------`);
setIsConnected(false);
onClose(event);
// 是否重新连接
// if (reconnectCount < reconnectAttrmpts) {
// reconnectTimerRef.current = setTimeout(() => {
// setReconnectCount(prevCount => prevCount + 1);
// connect();
// }, reconnectInterval);
// }
};
// 与 websocket 连接由于错误而关闭时触发
ws.onerror = event => {
console.error(`websocket error:`, event);
onClose(event);
};
wsRef.current = ws;
};
useEffect(() => {
connect();
return () => {
// 关闭连接
wsRef.current?.close();
clearTimeout(reconnectTimerRef.current);
};
}, []);
const sendMessage = (message: any): void => {
if (isConnected && wsRef.current) {
console.log(`-------websocket sending message: ${JSON.stringify(message)}--------`);
// 发送数据
wsRef.current.send(JSON.stringify(message));
} else {
console.error('cannot send message - websocket is not connected');
}
};
return [wsRef.current, sendMessage, newMessage, isConnected];
};
export default useWebsocket;