使用 JavaScript (Deno) 编写 WebSocket 服务器
此示例展示了如何使用 Deno 创建一个 WebSocket API 服务器,并附带一个网页。
Deno 是一个 JavaScript 运行时,支持 TypeScript 编译和即时缓存。Deno 内置了格式化程序、代码 linter、测试运行器等,还实现了许多 Web API。为了符合 Web 标准,所有 Deno 特定的 API 都在 Deno
命名空间下实现。
Deno 网站 提供了有关安装 Deno 的说明。
编写本文时使用的 Deno 版本:1.36
。
代码
代码将包含在两个文件中,一个用于服务器,另一个用于客户端。
服务器
创建一个名为 main.js
的文件。此文件将包含一个简单 HTTP 服务器的代码,该服务器还将提供客户端 HTML。
js
Deno.serve({
port: 80,
handler: async (request) => {
// If the request is a websocket upgrade,
// we need to use the Deno.upgradeWebSocket helper
if (request.headers.get("upgrade") === "websocket") {
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;
} else {
// 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);
}
},
});
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));
}
}
客户端
创建一个名为 index.html
的文件。此文件将包含一个脚本,该脚本将在连接建立后每五秒向服务器发送 ping 消息。
html
<!doctype html>
<h2>WebSocket Test</h2>
<p>Sends a ping every five seconds</p>
<div id="output"></div>
<script>
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}`);
};
</script>
运行代码
使用这两个文件,使用 Deno 运行应用程序。
shell
deno run --allow-net=0.0.0.0:80 --allow-read=./index.html main.js
Deno 需要我们为可以在主机上访问的内容提供显式权限。
--allow-net=0.0.0.0:80
允许应用程序连接到 localhost 的 80 端口--allow-read=./index.html
允许访问客户端的 HTML 文件