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中添加一个新元素。trueappendsocket.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授权。点击这里查看原文