跳到主要内容

使用 Websocket

WebSocket 是一种网络通信协议,它提供了在单个 TCP 连接上进行全双工通信的能力。与传统的 HTTP 请求-响应模式不同,WebSocket 允许服务器主动向客户端推送数据,实现了真正的双向通信。

主要特点:

  • 全双工通信:客户端和服务器可以同时发送和接收数据
  • 低延迟:建立连接后,数据传输的开销很小
  • 实时性:服务器可以主动推送数据,无需客户端轮询
  • 持久连接:一次握手后保持连接状态,避免重复建立连接

WebSocket 协议以 ws://wss://(安全连接)开头,使用标准的 HTTP 握手过程建立连接,之后升级为 WebSocket 协议进行通信。

本文介绍如何使用云托管(容器型和函数型)实现 Websocket 收发消息,并在客户端访问这些服务。

使用函数型云托管

在本地创建一个目录 websocket-demo,在目录中新建一个 index.js 文件,并编写以下代码:

exports.main = function (event, context) {
console.log({ event, context });
if (context.ws) {
const ws = context.ws;
ws.on("close", (msg) => {
console.log("close: ", msg);
ws.send("bye!");
});
ws.on("message", (msg) => {
console.log("message: ", msg);
ws.send(`echo: ${msg?.data}`);
});
}
};

exports.main.handleUpgrade = async function (upgradeContext) {
console.log(upgradeContext, "upgradeContext");
if (upgradeContext.httpContext.url === "/reject-upgrade") {
return {
allowWebSocket: false,
statusCode: 403,
body: JSON.stringify({ code: "code", message: "message" }),
contentType: "appliaction/json; charset=utf-8",
};
}
return { allowWebSocket: true };
};

这段代码实现了以下功能:

  • main 函数处理 WebSocket 连接后的消息交互:
    • 监听 close 事件,在连接关闭时发送告别消息
    • 监听 message 事件,收到消息时回复当前时间和消息内容
  • handleUpgrade 函数控制 WebSocket 连接的建立:
    • 当访问 /reject-upgrade 时拒绝连接
    • 其他路径允许建立 WebSocket 连接

部署调试

推荐使用 云开发 CLI 进行部署。

安装 CLI 并登录后,进入项目根目录,执行以下命令:

# 部署函数型云托管实例
tcb cloudrunfuntion deploy

实例部署完成以后,前往 云开发控制台

在左侧导航栏选择【云托管】, 在【服务列表】页面可以找到刚刚部署的实例,点击进入【服务详情】页面,在详情页可以找到默认域名。 将默认域名开头的 https:// 替换为 ws:// 或者 wss:// ,在 Postman 等工具中进行 WebSocket 连接测试。

使用容器型云托管

你可以使用代码示例,示例代码仓库地址

克隆代码仓库后,进入项目根目录,目录结构如下:

├── Dockerfile
├── app
│   └── server.js
└── package.json

其中 app/server.js 是使用 expressexpress-ws 实现的服务,云托管会根据 Dockerfile 来构建容器。

关于容器型云托管的更多信息,可以参考 服务开发说明

部署调试

推荐使用 云开发 CLI 进行部署。

安装 CLI 并登录后,进入项目根目录,执行以下命令:

# 部署容器型云托管实例
tcb cloudrun deploy

实例部署完成以后,前往 云开发控制台

在左侧导航栏选择【云托管】, 在【服务列表】页面可以找到刚刚部署的实例,点击进入【服务详情】页面,在详情页可以找到默认域名,我们假设创建的服务默认域名为:https://demo.ap-shanghai.run.tcloudbase.com,将默认域名开头的 https:// 替换为 ws:// 或者 wss:// 如:wss://demo.ap-shanghai.run.tcloudbase.com,在 Postman 等工具中进行 WebSocket 连接测试。

访问 websocket 服务

微信小程序

wx.cloud.init({
env: "xxxx-yyy", // 替换为你的环境 ID
});
const { socketTask } = await wx.cloud.connectContainer({
service: "websocket-demo", // 替换自己的服务名
path: "/", // 不填默认根目录
});

socketTask.onMessage(function (res) {
console.log("【WEBSOCKET】", res.data);
});
socketTask.onOpen(function (res) {
console.log("【WEBSOCKET】", "链接成功!");
socketTask.send({
data: "这是小程序消息",
});
});
socketTask.onClose(function (res) {
console.log("【WEBSOCKET】链接关闭!");
});

更新信息可以查看微信云托管文档

浏览器

const ws = new WebSocket("wss://demo.ap-shanghai.run.tcloudbase.com"); // 替换为你的服务地址
ws.onopen = function () {
console.log("链接建立成功");
ws.send("微信云托管测试信息"); // 发送消息
};
ws.onmessage = function (evt) {
console.log(evt.data);
};
ws.onclose = function () {
console.log("链接已经关闭");
};

Node.js

Node.js 中可以使用 ws 模块来实现 WebSocket 客户端。

import WebSocket from "ws";

function run() {
const ws = new WebSocket("wss://demo.ap-shanghai.run.tcloudbase.com"); // 替换为你的服务地址

ws.on("close", (code, reason) => {
console.log("close:", code, `${reason}`);
});
ws.on("error", (err) => {
console.error("error: ", err);
});
ws.on("upgrade", () => {
console.log("upgrade");
});
ws.on("ping", () => {
console.log("recv ping message");
});
ws.on("pong", () => {
console.log("recv pong message");
setTimeout(() => {
ws.ping();
}, 1000);
});
ws.on("unexpected-response", (ws, req, res) => {
// 非 upgrade 响应和 3xx 重定向响应认为是 unexpected-response
console.log("recv unexpected-response message");
});

ws.on("message", (data) => {
console.log("received: %s", data);
});

ws.on("open", () => {
ws.ping();
ws.send("string data");
ws.send(Buffer.from("buffer data"));
});
}

run();