WebSockets教程—创建一个实时的WebSocket服务器

1,774 阅读5分钟

WebSockets教程:创建一个实时WebSocket服务器

在本教程中,我们来看看如何创建一个WebSocket服务器,这将允许与你的用户进行实时互动。

我们用Javascript做的很多工作都涉及到我们从服务器来回发送信息。你可能对API的概念很熟悉,它以特定的格式向服务器或网站发送数据,以获得特定的响应。

这些被称为REST APIs。虽然很有用,但它们在持续的数据流方面不是很好。如果你试图用REST APIs做一些实时的事情,你将会有一个糟糕的时间。幸运的是,如果我们想与用户进行实时连接,我们有一个替代品,即Websockets

Websockets如何工作

Websockets 本质上是在服务器和你的计算机之间建立的持续连接。当你访问一个网站时,它可以向服务器发送一个GET 请求,以启动用户和服务器之间的WebSocket连接。

Websockets与REST API

如果用户离开网站,连接就会被切断,因此只要用户继续使用该网站,就只能访问Websocket。

Websocket可以保持开放多长时间?

一旦创建了WebSocket,理论上它可以永远保持开放。这方面有几个例外情况。

  • 服务器发生故障。 这将破坏WebSocket,但我们可以尝试重新连接它。
  • 停电或互联网连接问题:如果用户的互联网停止,连接将中断。
  • 不活动。 如果用户没有通过websocket进行交互或发送数据,连接将不可避免地超时。

因此,当我们设计网络套接字时,我们需要考虑,如果用户的连接因某种原因停止,我们如何重新连接它们,以避免中断用户的体验。

制作WebSocket

因此,Websocket由两部分组成:服务器和用户使用的本地机器。对于我们正在做的事情,我们将使用Node.JS作为我们的服务器,但其他语言也支持websocket。

当用户访问我们的网站时,我们会加载一个带有一些Javascript的文件,其中包含一个连接到我们的websocket的字符串。同时,在我们的后端,我们将设置websocket,用户将连接到它。这在下图中显示。

第1步:创建我们的服务器

让我们先为websocket连接创建我们的Node.JS网络服务器。为此,我们将使用一个Express服务器,它有一个额外的包,名为express-ws 。这个额外的包将允许我们以使用get 的方式使用ws

import path from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

import express from 'express'
import expressWs from 'express-ws'
import http from 'http'

// Our port
let port = 3000;

// App and server
let app = express();
let server = http.createServer(app).listen(port);    

// Apply expressWs
expressWs(app, server);

app.use(express.static(__dirname + '/views'));

// Get the route / 
app.get('/', (req, res) => {
    res.status(200).send("Welcome to our app");
});

// Get the /ws websocket route
app.ws('/ws', async function(ws, req) {
    ws.on('message', async function(msg) {
        console.log(msg);
        // Start listening for messages
    });
});

最后一个子句,app.ws ,指的是websocket,这就是我们要在前端尝试连接的东西。目前,websocket只在收到来自前端的信息时才会登录控制台。让我们改变它,让它发送一些东西回来。

// Get the /ws websocket route
app.ws('/ws', async function(ws, req) {
    ws.on('message', async function(msg) {
        // What was the message?
        console.log(msg);
        // Send back some data
        ws.send(JSON.stringify({
            "append" : true,
            "returnText" : "I am using websockets!"
        }));
    });
});

现在,每当这个websocket连接收到数据时,它就会发回一个对象,我们在上面定义了这个对象。然后,我们可以在我们的前端操作这个对象,为用户显示或改变视图。

第2步:在前台连接

正如我们之前提到的,当我们的用户访问我们的网站时,我们在HTML文档中向他们提供一些本地的javascript。我已经在index.html文件中为我们的演示添加了一些其他元素。

<script src="local.js"></script>
<p>Welcome to websockets. Click here to start receiving messages.</p>
<button id="websocket-button">Click me</button>
<div id="websocket-returns"></div>

接下来,我们需要把一些连接细节放在我们的local.js 文件中。我已经创建了一个单一的连接文件,我们在文件加载后运行它。它看起来像这样。

// @connect
// Connect to the websocket
let socket;
const connect = function() {
    return new Promise((resolve, reject) => {
        const socketProtocol = (window.location.protocol === 'https:' ? 'wss:' : 'ws:')
        const port = 3000;
        const socketUrl = `${socketProtocol}//${window.location.hostname}:${port}/ws/`
        
        // Define socket
        socket = new WebSocket(socketUrl);

        socket.onopen = (e) => {
            // Send a little test data, which we can use on the server if we want
            socket.send(JSON.stringify({ "loaded" : true }));
            // Resolve the promise - we are connected
            resolve();
        }

        socket.onmessage = (data) => {
            console.log(data);
            // Any data from the server can be manipulated here.
            let parsedData = JSON.parse(data.data);
            if(parsedData.append === true) {
                const newEl = document.createElement('p');
                newEl.textContent = parsedData.returnText;
                document.getElementById('websocket-returns').appendChild(newEl);
            }
        }

        socket.onerror = (e) => {
            // Return an error if any occurs
            console.log(e);
            resolve();
            // Try to connect again
            connect();
        }
    });
}

// @isOpen
// check if a websocket is open
const isOpen = function(ws) { 
    return ws.readyState === ws.OPEN 
}

要连接到websocket,我们必须使用ws://,而不是HTTP,以及wss://,而不是HTTPS。我们将其放入我们的new WebSocket() 函数,以生成我们的连接。在我们的连接函数中,我们有三个事件监听器。

  • socket.onopen: 如果连接成功并打开,这个事件就会触发。
  • socket.onmessage :任何时候服务器向我们发送一个消息,这个就会触发。在我们的例子中,如果我们的用户收到的数据设置为 ,我们将在用户的HTML中添加一个新元素。true append
  • socket.onerror :如果连接失败,或发生错误,这将触发。

让我们把这一切联系起来;由于我们在全局范围内存储了我们的socket变量,我们可以在连接成功后发送数据。下面的事件监听器连接到websocket,然后在用户点击我们的HTML按钮时向服务器发送数据。

当服务器收到这些数据时,它就会发回自己的数据,因为服务器的 "消息 "事件启动了。这些数据会返回给用户,然后在他们的文档中添加一个新元素。

javascript Copy // When the document has loaded document.addEventListener('DOMContentLoaded', function() { // Connect to the websocket connect(); // And add our event listeners document.getElementById('websocket-button').addEventListener('click', function(e) { if(isOpen(socket)) { socket.send(JSON.stringify({ "data" : "this is our data to send", "other" : "this can be in any format" })) } }); });


结论

就这样了!现在,我们有了一个正常运行的Websocket,它允许你向服务器发送数据并返回给用户。如果你想了解更多信息或下载源代码,这里有一些有用的链接:

发布于DZone,由DZone MVB的Johnny Simpson授权。点击这里查看原文