在前一篇文章 Deno2.0如何快速创建Restfulapi/静态文件托管应用及oak框架介绍 介绍了利用Deno2.0创建http服务端应用的方法,本文主要介绍如果利用它来构建Websocket全栈应用。而且,我可以大言不惭的称之为最佳的Websocket全栈应用js运行时。
在全栈开发中,WebSocket 是一种非常常见的实时通信方式,而 Deno 作为一个新兴的 JavaScript/TypeScript 运行时,为创建 WebSocket 提供了更加简便的方式。在本文中,我们将讨论如何利用 Deno 2.0 快速创建 WebSocket 服务端和客户端应用。让我们通过一个简单的代码示例,来探索 Deno 在 WebSocket 实现中的便捷与强大。
Deno Deploy 代码和在线测试环境
准备工作
在本篇内容中,我们将会实现以下功能:
- 创建一个 Deno 服务端,用于处理 WebSocket 请求。
- 创建客户端页面,用于连接并与 WebSocket 服务器交互。(因为编码简化,按钮使用英文Connect=连接)
- 在服务端代码中同时连接自身进行内部测试。
代码示例如下所示:
// 下面这个方法是前后端共用了 - 便于展示前后端接口一致性复用的好处
const createSocket = (url: string, startPing = false, isWeb = false) => {
const ws = new WebSocket(url);
ws.onopen = () => {
console.log(`ws open isWeb: ${
isWeb}`);
if (startPing) ws.send('ping');
};
ws.onmessage = (ev) => {
console.log(`message:`, ev.data);
if (isWeb) document.querySelector('#msg').innerText = ev.data;
};
ws.onerror = (err) => {
console.log(`ws err isWeb: ${
isWeb}`);
console.error(err);
};
};
Deno.serve((req) => {
if (req.headers.get("upgrade") !== "websocket") {
return new Response(`
<div id=msg> messages </div>
<script>
// 这里就把共用的代码用最简单的方式传回给web前端,
const createSocket = ${
String(createSocket)};
window.connect = () => createSocket('wss://' + location.host, true, true);
</script>
<button onclick="connect()">Connect</button>
`, {
headers: {
'content-type': 'text/html'
}
});
}
const {
socket, response } = Deno.upgradeWebSocket(req);
socket.addEventListener("open", () => {
console.log("a client connected!");
});
socket.addEventListener("message", (event) => {
if (event.data === "ping") {
socket.send("pong");
}
});
return response;
});
setTimeout(() => {
// 这里就是服务端直接跑一个客户端连接刚刚起来的服务端应用
console.log(`server side client`);
createSocket("wss://afraid-boar-70.deno.dev", true, false);
});
服务器端的websocket客户端连接:
客户端的websocket客户端连接(点了connect之后)
代码解析
服务端和客户端的集成
在上述代码中,Deno.serve()
方法用于创建一个 HTTP 服务器,并根据请求类型处理不同的响应:
- 当请求头中不包含
"upgrade" : "websocket"
时,返回一个简单的 HTML 页面,该页面包含一个按钮用于手动连接到 WebSocket 服务端。 - 当请求为 WebSocket 连接时,通过
Deno.upgradeWebSocket(req)
升级请求,并创建 WebSocket 连接。
客户端连接
我们在 HTML 中通过 <button>
元素来触发客户端 WebSocket 连接,并使用 createSocket()
函数来实现连接逻辑。该函数通过 JavaScript 原生的 WebSocket
对象来建立连接,并添加了一些监听事件用于响应连接的状态变化和消息接收。
createSocket(url: string, startPing = false, isWeb = false)
函数的主要逻辑:
- onopen: 在 WebSocket 连接建立后调用,输出连接信息,并根据
startPing
参数发送 "ping" 消息。 - onmessage: 在收到服务端消息时调用,输出消息内容,如果是网页端,则在页面上更新显示消息。
- onerror: 在 WebSocket 出现错误时调用,输出错误信息。
服务端内部客户端连接
为了测试 WebSocket 连接,代码中还使用 setTimeout()
创建了一个延时调用,在服务端启动后通过 createSocket("wss://afraid-boar-70.deno.dev", true, false)
进行 WebSocket 客户端连接。这样可以让服务端自身成为一个客户端,与自己进行消息通信。
WebSocket 服务端处理流程
下面是一个使用 Mermaid 绘制的图,表示 WebSocket 服务端应用每个连接的处理流程:
graph TD
A[接收请求] --> B{请求类型}
B -- 非 WebSocket 请求 --> C[返回 HTML 页面]
B -- WebSocket 请求 --> D[升级为 WebSocket]
D --> E[监听 open 事件]
E --> F[客户端连接成功]
D --> G[监听 message 事件]
G --> H{消息类型}
H -- ping --> I[发送 pong]
运行示例(本地)
要运行这段代码,首先确保您已经安装了 Deno 运行时。然后可以通过以下命令运行代码:
deno run --allow-net your_file.ts
运行后,Deno 会启动一个 WebSocket 服务器,您可以在浏览器中访问相应的地址来看到网页客户端部分,点击 "Connect" 按钮即可连接到服务器并发送 ping 消息。
与 Node.js 创建 WebSocket 服务端应用的对比
在 Node.js 中创建 WebSocket 服务端通常需要借助第三方库,例如 ws
或 socket.io
。以下是与 Deno 创建 WebSocket 服务端的对比:
- 依赖性:Deno 自带 WebSocket 支持,无需额外安装依赖,而在 Node.js 中,需要安装如
ws
或socket.io
等库。 - 代码复杂性:使用 Deno 创建 WebSocket 服务端相对简单,只需调用
Deno.serve()
和Deno.upgradeWebSocket()
。在 Node.js 中,通常需要编写更多的代码来处理 WebSocket 升级和连接。
例如,在 Node.js 中使用 ws
创建 WebSocket 服务器的代码如下:
const WebSocket = require('ws');
const wss = new WebSocket.Server({
port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function message(data) {
console.log('received: %s', data);
if (data === 'ping') {
ws.send('pong');
}
});
ws.send('connected');
});
与 Deno 相比,Node.js 的实现需要手动处理端口、连接事件等,相对复杂一些。但使用 socket.io
这样的库,可以提供更丰富的功能,例如房间管理、自动重连等。
与 Node.js 创建 WebSocket 客户端的对比
在 Node.js 中创建 WebSocket 客户端也需要依赖 ws
库,而在 Deno 中可以直接使用与前端一致的 WebSocket 接口进行连接,这使得代码更加统一,开发体验更好。
在 Deno 中,我们使用 WebSocket
对象来建立客户端连接,与前端 JavaScript 的使用方式完全相同,例如:
const ws = new WebSocket('wss://example.com');
而在 Node.js 中,代码如下:
const WebSocket = require('ws');
const ws = new WebSocket('wss://example.com');
ws.on('open', function open() {
console.log('connected');
ws.send('ping');
});
ws.on('message', function message(data) {
console.log('received: %s', data);
});
Node.js 使用 ws
库来模拟浏览器中的 WebSocket
对象,但需要手动引入库,这使得代码在不同环境下不一致。而 Deno 则可以直接使用标准的 WebSocket 接口,这对于前端开发者来说更加自然和方便。
Deno、Bun 和 Node.js 对于 WebSocket 支持的对比
下表列出了 Deno、Bun 和 Node.js 在创建 WebSocket 服务端应用时的特性对比:
特性 | Deno | Bun | Node.js (ws/socket.io) |
---|---|---|---|
内置 WebSocket 支持 | 是 | 否,需要额外库 | 否,需要额外库 |
升级 WebSocket 方法 | Deno.upgradeWebSocket() |
使用第三方库实现 | 使用 ws 或 socket.io |
依赖库 | 无需额外依赖 | 需要第三方库 | 需要 ws 或 socket.io |
代码复杂性 | 简单 | 依赖库特性,视实现而定 | 代码较多,依赖第三方库 |
性能 | 高效 | 高效 | 依赖库性能 |
下表列出了 Deno、Bun 和 Node.js 在创建 WebSocket 客户端应用时的特性对比:
特性 | Deno | Bun | Node.js (ws) |
---|---|---|---|
WebSocket API 一致性 | 与前端一致 | 依赖库特性,可能不同 | 与前端不同,需要 ws 库 |
内置支持 | 是 | 否,需要额外库 | 否,需要 ws 库 |
依赖库 | 无需额外依赖 | 需要第三方库 | 需要 ws 库 |
代码复杂性 | 简单,与前端一致 | 依赖库特性,视实现而定 | 代码较多,需引入库 |
总结
通过上述代码示例,我们可以看到 Deno 提供了简洁高效的 WebSocket 支持,无需额外依赖包便可以快速搭建一个具备基本功能的 WebSocket 服务端和客户端。对于想要学习全栈开发的前端开发者来说,Deno 是一个值得尝试的新工具,它具有现代化的开发体验,同时又兼具简单易用的特性。希望这篇文章能帮助您迈出使用 Deno 的第一步,搭建自己的 WebSocket 应用。
怎么说呢?刚开始搭建这个后端的时候,我还走了不少弯路子,还在用Nodejs的思维 - -,实际上Deno简化了很多,作为客户端直接用Websocket就可以,而我还在jsr搜索。Deno2.0值得学习和使用,反正我是在慢慢的重写一个实时的应用了。