闽公网安备 35020302035485号



Connection: Upgrade 是与Upgrade: websocket 进行配合使用的,它的作用是告诉服务器,不要把这个请求当作普通的 HTTP 请求来处理,而是要关注 “Upgrade” 请求头中的内容,按照要求进行协议的升级。
服务器收到客户端的升级请求后,如果支持 Web Socket 协议,就会返回一个响应来完成握手过程。响应状态码通常是 101,表示 协议切换。响应头也会包含和客户端请求对应的 Upgrade 和 Connection 字段,确认连接升级。Sec - WebSocket - Accept ,它是根据客户端请求中的 Sec - WebSocket - Key 生成的,用于安全验证。通过这个握手过程,双方就建立了一个稳定的 Web Socket 连接这样,这个连接是基于 TCP的,为后续的双向通信做好了准备。
我们从下图中可以看出,Web socket全双工通道的特点,客户端可以向服务端主动发送消息,服务端也可以推送数据到服务端。具体的数据格式,我们可以通过抓包软件来进行抓包看下。
在整个通信过程中,Web Socket 协议要求客户端和服务器都要维护连接的状态。连接状态包括连接是否打开、正在关闭或者已经关闭等。客户端和服务器通过心跳机制(发送周期性的小数据包来检测对方是否还在线)或者其他自定义的连接检测方法来确保连接的稳定性。
当需要关闭 WebSocket 连接时,无论是客户端还是服务器都可以发起关闭请求。关闭请求也是通过发送一个特定的帧(关闭帧)来实现的。对方在收到关闭帧后,会进行一些必要的清理工作,如释放资源等,然后关闭连接。
<div id="app">
<input v-model="message" placeholder="输入要发送的消息" />
<button @click="sendMessage">发送消息</button>
<div>
<h3>收到的回复记录:</h3>
<ul>
<li v-for="(msg, index) in receivedMessages" :key="msg">{{ msg }}</li>
</ul>
</div>
</div>
<script>
const app = new Vue({
el: "#app",
data() {
return {
message: "",
receivedMessages: [], // 新增数组用于存储所有收到的消息
socket: null,
};
},
mounted() {
// 创建WebSocket连接,这里的地址要和后端服务器监听的地址对应,这里假设后端在本地3000端口
this.socket = new WebSocket("ws://localhost:3000");
// 连接成功时触发的事件
this.socket.addEventListener("open", () => {
console.log("已连接到WebSocket服务器");
});
// 接收服务器发送消息的事件
this.socket.addEventListener("message", (event) => {
const receivedMsg = event.data;
this.receivedMessages.push(receivedMsg); // 将收到的消息添加到数组中
});
// 堆代码 duidaima.com
// 连接关闭时触发的事件
this.socket.addEventListener("close", () => {
console.log("与WebSocket服务器的连接已关闭");
});
},
methods: {
sendMessage() {
if (this.socket.readyState === WebSocket.OPEN) {
this.socket.send(this.message);
this.message = "";
} else {
console.log("WebSocket连接未就绪,无法发送消息");
}
},
},
});
</script>
模拟服务端发送请求const WebSocket = require('ws');
// 创建WebSocket服务器实例,监听在3000端口,你可以根据需求修改端口号
const wss = new WebSocket.Server({ port: 3000 });
// 用于存储已连接的客户端WebSocket实例,方便后续向所有客户端发送消息等操作
const clients = [];
// 当有客户端连接时触发的事件
wss.on('connection', (ws) => {
console.log('客户端已连接');
clients.push(ws);
// 接收客户端发送的消息
ws.on('message', (message) => {
console.log(`收到客户端消息: ${message}`);
// 这里简单地将收到的消息加上一个后缀后再发回客户端
const responseMessage = `你发送的消息是:${message}`;
ws.send(responseMessage);
});
// 当客户端关闭连接时触发的事件
ws.on('close', () => {
console.log('客户端已断开连接');
const index = clients.indexOf(ws);
if (index > -1) {
clients.splice(index, 1);
}
});
});
// 【注意: 模拟一个定时任务,每隔1秒向所有已连接的客户端发送一条消息,你可以编写自己的业务代码】
setInterval(() => {
const messageToSend = '这是服务端主动发送的消息,当前时间:' + new Date().toLocaleString();
clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(messageToSend);
}
});
}, 1000);
console.log('WebSocket服务器已启动,正在监听3000端口...');
实现效果

const express = require('express');
const app = express();
const port = 3000;
// 设置响应头,表明这是一个SSE流
app.get('/events', (req, res) => {
res.setHeader('Content-Type','text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// 【注意:模拟定时发送数据(实际应用中需要根据真实业务逻辑触发发送)!!!】
const interval = setInterval(() => {
const data = `data: { "time": "${new Date().toLocaleString()}"}\n\n`;
res.write(data);
}, 3000);
// 当客户端关闭连接时,清除定时器
req.on('close', () => {
clearInterval(interval);
});
});
app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`);
});
模拟客户端代码
mounted() {
const source = new EventSource('http://localhost:3000/events');
source.onmessage = (event) => {
const data = JSON.parse(event.data); // data 就是发送的消息
this.message = data.message;
};
source.onerror = (error) => {
console.log('SSE连接出错:', error);
};
}
实现效果