用 JavaScript (Deno) 编写 WebSocket 服务器
本示例将向您展示如何使用 Deno 创建一个 WebSocket API 服务器,并附带一个配套的网页。
Deno 是一个 JavaScript 运行时,支持即时 TypeScript 编译和缓存。Deno 内置了格式化器、linter、测试运行器等工具,并实现了许多 Web API。通过符合 Web 标准,所有 Deno 特有的 API 都在 Deno 命名空间下实现。
您可以访问 Deno 网站获取 Deno 的安装说明。
撰写本文时使用的 Deno 版本:1.36。
代码
代码将包含在两个文件中:一个用于服务器,一个用于客户端。
Server
创建一个 main.js 文件。该文件将包含一个简单的 HTTP 服务器代码,该服务器还将提供客户端 HTML。
js
Deno.serve({
port: 80,
async handler(request) {
if (request.headers.get("upgrade") !== "websocket") {
// If the request is a normal HTTP request,
// we serve the client HTML file.
const file = await Deno.open("./index.html", { read: true });
return new Response(file.readable);
}
// If the request is a websocket upgrade,
// we need to use the Deno.upgradeWebSocket helper
const { socket, response } = Deno.upgradeWebSocket(request);
socket.onopen = () => {
console.log("CONNECTED");
};
socket.onmessage = (event) => {
console.log(`RECEIVED: ${event.data}`);
socket.send("pong");
};
socket.onclose = () => console.log("DISCONNECTED");
socket.onerror = (error) => console.error("ERROR:", error);
return response;
},
});
Deno.upgradeWebSocket() 会将连接升级为 WebSocket 连接,这在 协议升级机制中有更详细的解释。
Deno.serve() 在底层使用了 Deno.listen() 和 Deno.serveHttp(),是一个用于轻松设置 HTTP 服务器的更高级别的接口。如果没有它,代码看起来会是这样的。
js
for await (const conn of Deno.listen({ port: 80 })) {
for await (const { request, respondWith } of Deno.serveHttp(conn)) {
respondWith(handler(request));
}
}
Client
创建一个 index.html 文件。该文件将在建立连接后每五秒 ping 一次服务器。它还应包含以下标记:
html
<h2>WebSocket Test</h2>
<p>Sends a ping every five seconds</p>
<div id="output"></div>
js
const wsUri = "ws://127.0.0.1/";
const output = document.querySelector("#output");
const websocket = new WebSocket(wsUri);
let pingInterval;
function writeToScreen(message) {
output.insertAdjacentHTML("afterbegin", `<p>${message}</p>`);
}
function sendMessage(message) {
writeToScreen(`SENT: ${message}`);
websocket.send(message);
}
websocket.onopen = (e) => {
writeToScreen("CONNECTED");
sendMessage("ping");
pingInterval = setInterval(() => {
sendMessage("ping");
}, 5000);
};
websocket.onclose = (e) => {
writeToScreen("DISCONNECTED");
clearInterval(pingInterval);
};
websocket.onmessage = (e) => {
writeToScreen(`RECEIVED: ${e.data}`);
};
websocket.onerror = (e) => {
writeToScreen(`ERROR: ${e.data}`);
};
运行代码
使用这两个文件,通过 Deno 运行应用程序。
sh
deno run --allow-net=0.0.0.0:80 --allow-read=./index.html main.js
Deno 要求我们为访问主机上的内容提供明确的权限。
--allow-net=0.0.0.0:80允许应用程序连接到本地主机上的 80 端口。--allow-read=./index.html允许访问客户端的 HTML 文件。