WebSocket的使用场景:
-
实时游戏:WebSocket可以用于实现在线多人游戏的实时交互。
-
聊天应用:即时通讯和聊天室可以通过WebSocket实现实时消息传递。
-
股票行情:实时股票交易平台可以利用WebSocket推送最新的市场数据。
-
协作工具:在线文档编辑或实时绘图工具等协作平台可以使用WebSocket来同步用户操作。
-
WebSocket是一种网络通信协议,它提供了在单个TCP连接上进行全双工通信的能力。这意味着数据可以在客户端和服务器之间双向流动,而无需客户端通过轮询或重复请求来获取更新。
客户端实现
-
创建WebSocket连接:使用
new WebSocket(url)
构造函数创建一个新的WebSocket对象,其中url
是WebSocket服务器的地址。 -
设置事件处理程序:为WebSocket对象设置各种事件处理程序,如
onopen
、onmessage
、onerror
和onclose
。 -
发送消息:当WebSocket连接成功建立后(即
onopen
事件触发时),客户端可以通过调用send
方法发送消息。 -
接收消息:当服务器发送消息时(即
onmessage
事件触发时),客户端可以接收消息。 -
关闭连接:当不再需要WebSocket连接时,可以调用
close
方法关闭连接。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>WebSocket Chat Example</title> <script> // 当文档加载完毕时执行 document.addEventListener('DOMContentLoaded', function() { var ws; var chatBox = document.getElementById('chatBox'); var messageInput = document.getElementById('messageInput'); var sendButton = document.getElementById('sendButton'); // 尝试连接到WebSocket服务器 function connect() { ws = new WebSocket("ws://localhost:8080"); ws.onopen = function() { console.log('WebSocket 连接成功'); }; ws.onmessage = function(event) { console.log('收到消息:', event.data); chatBox.textContent += event.data + '\n'; }; ws.onerror = function(error) { console.error('WebSocket 出现错误:', error); }; ws.onclose = function() { console.log('WebSocket 连接关闭'); }; } // 发送消息 function sendMessage() { if (ws.readyState === WebSocket.OPEN) { ws.send(messageInput.value); messageInput.value = ''; } else { console.error('WebSocket 连接未建立'); } } // 绑定按钮点击事件 sendButton.onclick = function() { sendMessage(); }; // 自动连接WebSocket connect(); }); </script> </head> <body> <h1>WebSocket Chat</h1> <pre id="chatBox"></pre> <input type="text" id="messageInput"> <button id="sendButton">发送</button> </body> </html>
服务器端实现
服务器端的实现会依赖于你选择的后端技术。以下是使用Node.js和ws库的一个简单示例:
示例代码(Node.js + ws):
const WebSocket = require('ws'); const server = new WebSocket.Server({ port: 8080 }); server.on('connection', function(socket) { console.log('新客户端已连接'); // 监听客户端发送的消息 socket.on('message', function(message) { console.log('收到消息:', message); // 将收到的消息广播给所有客户端 server.clients.forEach(function(client) { if (client.readyState === WebSocket.OPEN) { client.send(message); } }); }); socket.on('close', function() { console.log('客户端已断开连接'); }); });
在这个例子中,服务器会监听8080端口上的WebSocket连接。每当有新消息时,它将消息广播给所有连接的客户端。
轻量级推送技术SSE
SSE利用HTTP连接来实现服务器到客户端的单向通信。一旦客户端通过EventSource接口连接到服务器,服务器就可以发送数据到客户端。客户端接收到数据后,默认会触发message事件。
特点
-
基于HTTP:SSE使用标准的HTTP协议,因此易于实现和部署。
-
单向通信:SSE主要用于服务器向客户端的单向数据推送,不支持客户端向服务器的推送。
-
轻量级:与WebSocket相比,SSE更简单,不需要复杂的握手过程。
-
自动重连:如果连接断开,SSE会自动尝试重连。
-
文本数据:SSE主要推送文本数据,对于二进制数据需要进行编码。
使用场景
-
实时更新:如股票价格、体育比赛得分等。
-
社交媒体:实时显示好友动态、消息通知等。
-
新闻网站:实时推送新闻头条。
-
在线游戏:推送游戏状态更新。
数据格式
SSE 协议非常简单,正常的Http请求,更改请起头相关配置即可
Content-Type: text/event-stream,utf-8
Cache-Control: no-cache
Connection: keep-alive
发送的文本流,用UTF8格式编码。文本事件流的消息由两个换行符分开,以冒号开头的为注释行,会被忽略。
发送的文本流,用UTF8格式编码。文本事件流的消息由两个换行符分开,以冒号开头的为注释行,会被忽略。
文本流字段
event: 用于标识事件类型的字符串,如果没有指定event,浏览器默认认为是message。
data: 消息的数据字段,当EventSource收到多个``data:``开头的连续行时,会将它们连接起来,在它们之间插入一个换行符。末尾的换行符也会被删除。
id: 事件ID,会被设置为当前EventSource对象的内部属性“最后一个事件ID”的值。
retry: 重新连接的时间。如果与服务器的连接丢失,浏览器会等待指定的时间,然后重新连接。retry必须是一个整数,它的单位是毫秒。
实现
服务器端
服务器端使用express框架创建一个持久的HTTP连接,并在有新数据时发送数据到客户端。数据通常以纯文本格式发送,并且每条消息之间以一对换行符分隔。
const express = require('express') //引用框架
const app = express() //创建服务
const port = 8088 //项目启动端口
//设置跨域访问
app.all('*', function (req, res, next) {
//设置允许跨域的域名,*代表允许任意域名跨域
res.header('Access-Control-Allow-Origin', '*')
//允许的header类型
res.header(
'Access-Control-Allow-Headers',
'Content-Type, Authorization, X-Requested-With'
)
//跨域允许的请求方式
res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS')
// 可以带cookies
res.header('Access-Control-Allow-Credentials', true)
if (req.method == 'OPTIONS') {
res.sendStatus(200)
} else {
next()
}
})
app.get('/sse', (req, res) => {
res.set({
'Content-Type': 'text/event-stream', //设定数据类型
'Cache-Control': 'no-cache', // 长链接拒绝缓存
'Connection': 'keep-alive', //设置长链接
})
console.log('进入到长连接了')
//持续返回数据
setInterval(() => {
console.log('正在持续返回数据中ing')
const data = {
message: `当前时间: ${new Date().toLocaleTimeString()}`,
}
res.write(`data: ${JSON.stringify(data)}\n\n`)
}, 1000)
// 当客户端断开连接时,清理资源
req.on('close', () => {
clearInterval() // 清除定时器
res.end() // 结束响应
})
})
//创建项目
app.listen(port, () => {
console.log(`项目启动成功-http://localhost:${port}`)
})
客户端
客户端使用EventSource接口来接收服务器推送的数据。以下是一个基本的客户端实现示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul id="ul">
</ul>
</body>
<script>
//生成li元素
function createLi(data) {
let li = document.createElement("li");
li.innerHTML = String(data.message);
return li;
}
//判断当前浏览器是否支持SSE
let source = ''
if (!!window.EventSource) {
source = new EventSource('http://localhost:8088/sse/');
} else {
throw new Error("当前浏览器不支持SSE")
}
//对于建立链接的监听
source.onopen = function (event) {
console.log(source.readyState);
console.log("长连接打开");
};
//对服务端消息的监听
source.onmessage = function (event) {
console.log(JSON.parse(event.data));
console.log("收到长连接信息");
let li = createLi(JSON.parse(event.data));
document.getElementById("ul").appendChild(li)
};
//对断开链接的监听
source.onerror = function (event) {
console.log(source.readyState);
console.log("长连接中断");
};
</script>
</html>
也可以用封装好得库 如microsoft/fetch-event-source
npm install @microsoft/fetch-event-source
https://www.npmjs.com/package/@microsoft/fetch-event-source
参考地址
MQTT app客户端常用方案,很多第三方推送平台也用它封装。