📌 面试答不上的问题
2️⃣ WebSocket
WebSocket 是基于 TCP 全双工通信 的协议,允许客户端和服务器之间进行实时双向通信,适用于聊天、游戏、协同编辑等场景。
🔹 工作原理
- 客户端通过
ws://
或wss://
(加密)协议向服务器发起握手请求。 - 服务器返回 101 状态码,升级 HTTP 连接为 WebSocket 连接。
- 双方可以双向发送消息,且不需要每次请求都建立新连接。
🔹 WebSocket 状态图示
状态 | 描述 | 值 | 事件 |
---|---|---|---|
CONNECTING | 正在建立连接 | 0 | open |
OPEN | 连接成功,可以进行通信 | 1 | message |
CLOSING | 连接正在关闭中 | 2 | close |
CLOSED | 连接已关闭,无法再通信 | 3 | close (连接关闭) |
🔹 WebSocket 相关事件
WebSocket 提供了多个事件,用于处理不同的连接状态和数据通信场景。
-
open
事件当 WebSocket 连接成功建立时触发。通常用于初始化连接后的一些操作,比如向服务器发送一条连接成功的消息。
javascriptconst socket = new WebSocket("wss://example.com"); socket.onopen = (event) => { console.log("连接成功!"); socket.send("Hello Server!"); };
-
message
事件当服务器发送消息到客户端时,
message
事件会被触发。可以通过event.data
获取服务器返回的数据。javascriptsocket.onmessage = (event) => { console.log("收到服务器消息:", event.data); };
-
error
事件如果 WebSocket 连接发生错误(如网络问题或服务器崩溃),
error
事件会被触发。可以通过这个事件捕获连接错误并进行处理。javascriptsocket.onerror = (event) => { console.error("WebSocket 发生错误:", event); };
-
close
事件当 WebSocket 连接关闭时(无论是正常关闭还是发生错误),
close
事件会被触发。可以通过该事件来清理一些资源或者执行断开连接后的操作。javascriptsocket.onclose = (event) => { if (event.wasClean) { console.log(`连接正常关闭,代码 ${event.code},原因: ${event.reason}`); } else { console.error("连接异常关闭!"); } };
📌 实现方式
🔹 服务器端(Node.js + ws 库)
javascript
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3000 });
wss.on('connection', ws => {
console.log('Client connected');
ws.send(JSON.stringify({ message: 'Welcome to WebSocket' }));
ws.on('message', msg => {
console.log('Received:', msg);
ws.send(`Server received: ${msg}`);
});
ws.on('close', () => console.log('Client disconnected'));
});
🔹 客户端(浏览器)
javascript
const ws = new WebSocket('ws://localhost:3000');
ws.onopen = () => {
console.log('Connected to server');
ws.send('Hello Server!');
};
ws.onmessage = event => {
console.log('Message from server:', event.data);
};
ws.onclose = () => console.log('Connection closed');
🔹 Uniapp(多端支持)
📌 片段有点长 还请耐心阅读
API - uni.request封装
主要步骤:
ConnectChatSocket(data)
:这是对话的 WebSocket 请求方法,传入data
参数。request
:request
是一个封装了请求发送逻辑的工具函数,能够处理不同类型的请求(如 HTTP 请求和 WebSocket 请求)。通过isWebSocket: true
来标识这次请求是一个 WebSocket 连接请求。wss://baidu.com/api/ws
:这是 WebSocket 服务器的地址。注意,WebSocket 使用的是wss://
协议(即 WebSocket Secure),与 HTTP 的https://
协议类似,提供加密传输。
javascript
// 流式请求-用于SSE
async function chunkedRequest(options = {}) {
if (!options?.enableChunked) return;
options.complete = () => ""; // 避免默认回调
const requestTask = uni.request(options);
if (typeof options?.TaskCallBack === "function") {
requestTask.onChunkReceived((res) => options.TaskCallBack(res));
}
return requestTask;
}
// WebSocket 请求
async function socketRequest(options = {}) {
if (!options?.isWebSocket) return;
const requestTask = uni.connectSocket({
url: `${options.url}?token=${store.state.user.tokenData}`,
header: options?.header || {},
method: options?.method || "GET",
complete: () => "",
});
return requestTask;
}
// 统一请求封装
export default async function request(options = {}) {
try {
options = await interceptorsRequest(options); // 请求拦截
if (options?.enableChunked) return chunkedRequest(options);
if (options?.isWebSocket) return socketRequest(options);
const [err, response] = await uni.request(options);
return interceptorsResponse(err, response, options); // 响应拦截
} catch (e) {
return Promise.reject(e);
}
}
// 对话 - WebSocket
function ConnectChatSocket(data) {
return request({
method: "GET", // 请求方法为 GET(WebSocket 不关心 HTTP 方法,但会使用 WebSocket 协议)
url: "wss://baidu.com/api/ws", // WebSocket 服务端地址,使用 `wss://` 协议
isWebSocket: true, // 自定义字段,标记这是 WebSocket 请求
data, // 传递的数据,用于初始化连接时的消息或身份验证等
});
},
Vuex数据管理中封装 chat.js
javascript
// WebSocket 连接状态
export const SOCKET_STATUS = {
CONNECTED: 1, // 连接成功
PADDING_MSG: 2, // 发送消息成功 | 等待消息
SEND_MSG_ERR: 3, // 发送消息失败
CLOSED: 4, // 已断开
ERRORED: 5, // 错误
};
创建 WebSocket 连接 (createWebSocket
)
javascript
async createWebSocket({ state, commit }, data) {
const { isRefresh, MsgCallBack } = data || {};
if (!isRefresh && state?.contentSocket) return state.contentSocket;
const [, connect] = await apiFetch.Chat.ConnectChatSocket();
if (!connect || typeof connect?.onOpen !== "function") {
// 连接失败
commit("SET_CONTENT_SOCKET_STATUS", SOCKET_STATUS.ERRORED);
return null;
}
await new Promise((resolve) => {
connect.onOpen(() => {
commit("SET_CONTENT_SOCKET_STATUS", SOCKET_STATUS.CONNECTED);
resolve(true);
});
connect.onMessage((res) => {
if (typeof MsgCallBack === "function") {
MsgCallBack(res);
}
});
connect.onClose((res) => {
console.error("WebSocket 已断开", res);
commit("SET_CONTENT_SOCKET_STATUS", SOCKET_STATUS.CLOSED);
resolve(false);
});
connect.onError(() => {
console.error("WebSocket 发生错误");
Toast("连接服务器错误!");
commit("SET_CONTENT_SOCKET_STATUS", SOCKET_STATUS.ERRORED);
resolve(false);
});
});
commit("SET_CONTENT_SOCKET", connect);
return connect;
},
发送消息 (sendSocket
)
javascript
async sendSocket({ state, commit, dispatch }, data) {
if (
!state.contentSocket ||
typeof state.contentSocket?.send !== "function" ||
state.contentSocketStatus !== SOCKET_STATUS.CONNECTED
)
return Promise.resolve(false);
const isSend = await new Promise((resolve) => {
const sendData = {
id: data?.id || null,
msg: data?.msg || "",
type: data?.type || state.curChatModel || CHAT_MODEL.DEEPSEEK,
};
commit("SET_CONTENT_SOCKET_STATUS", SOCKET_STATUS.PADDING_MSG);
state.contentSocket.send({
data: JSON.stringify(sendData),
success: () => {
if (!data?.id) {
setTimeout(() => {
dispatch("GetUserSessionsList", {
isRefresh: true,
notRefreshLog: true,
});
}, 2000);
}
resolve(true);
},
fail: (res) => {
console.error("发送消息失败", res);
commit("SET_CONTENT_SOCKET_STATUS", SOCKET_STATUS.SEND_MSG_ERR);
resolve(false);
},
complete: () => {
dispatch("AddSessionsLog", { type: REPLY_TYPE.REPLY });
},
});
});
return isSend;
},
关闭 WebSocket (closeSocket
)
javascript
closeSocket({ state, commit }, data) {
if (!state.contentSocket || typeof state.contentSocket?.close !== "function") return;
console.error("关闭会话连接");
state.contentSocket.close({ ...(data || {}), code: data?.code || 1000 });
commit("SET_CONTENT_SOCKET", null);
commit("SET_CONTENT_SOCKET_STATUS", SOCKET_STATUS.CLOSED);
},
📌 特点
✅ 全双工通信 ,支持客户端和服务器双向传输数据 。
✅ 适用于高频交互 (如 IM 聊天、在线游戏)。
✅ 支持二进制数据 (如文件、视频流)。
❌ 需要单独的 WebSocket 服务器,不能直接通过 HTTP 服务器处理。