使用 websocket 服务器是加速应用程序的好方法。API 固有地带有自己的 HTTP 开销,这意味着每次调用 API 时,都必须等待一点 HTTP 响应。
这大部分都很好,但是如果您的应用程序具有大量时间敏感且频繁的服务器请求,则可能会成为问题。一个很好的例子是聊天应用程序,您需要在其中立即查看对方在说什么。API 仍然可以在这种情况下工作,但它不是该工作的最佳解决方案。
在本教程中,我们将介绍如何使用 Node.JS 和 express 中构建的 websocket 服务器在 Vue.JS 中设置 websocket 服务器。继续阅读以获取更多信息。我还在这里写了另一个关于如何在 Express 和 Javascript 中创建 websocket 服务器的教程。
入门:创建您的 Vue 应用程序#
像往常一样,使用 vue cli 启动一个 vue 应用程序。例如,编写以下代码以生成一个名为“fjolt-app”的 vue 应用程序:
vue create fjolt-app
如果这不起作用,请尝试通过 npm 安装 vue cli 工具。包可以在这里找到。
如果您是 Vue 的新手,您可以通过npm run serve
在您创建应用程序的目录中运行来启动这个虚拟应用程序。
创建一个 websocket 服务器#
下一步是创建一个 websocket 服务器。如前所述,我在这里写了一篇关于如何做到这一点的深入教程。总之,您需要创建一个 index.js 文件。为了让事情变得更简单,我在 vue 目录本身中创建了我的,并将其命名为index.mjs,这样我就可以立即使用 import 语句。
然后我的文件结构如下所示:
| - node_modules | - package.lock.json | - package.json | - public | - README.md | - src | - App.vue < -- 我们的应用! | - assets | - components | - main.js | - index.mjs <-- 我们的 websocket 服务器
用 Javascript 创建我们的 websocket 服务器
接下来,让我们创建我们的 websocket 索引文件。在index.mjs
中,如果您感到懒惰,可以使用以下代码。不要忘记npm i
您导入的所有模块。
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);
ws.send(JSON.stringify({ "message" : "hello" }));
// Start listening for messages
});
});
所以客户端会将数据发送到我们的 websocket 服务器。该数据将作为msg
变量到达,如上面代码的底部所示。然后,我们可以获取、存储或处理该消息数据。有时,我们可能希望将其发送到数据库。其他时候,我们可能想把它发回给用户。
无论哪种方式,ws.on
我们都可以将消息发送回客户端。比方说,当收到一条消息时,我想向用户发送一个{ "message" : "hello" }
回复给用户的对象。为此,我将执行以下操作:
// Get the /ws websocket route
app.ws('/ws', async function(ws, req) {
ws.on('message', async function(msg) {
// Let's put our message in JSON.stringify, and send it to the user who just sent the message
ws.send(JSON.stringify({ "message" : "hello" }));
});
});
当我们对我们的 websocket 服务器感到满意时,我们可以在终端中通过键入 运行它node index.mjs
,同时在index.mjs所在的目录中运行它。现在我们有了一个可以连接的实时 websocket。
简而言之,我们现在有一种方法可以在我们的服务器和用户之间创建直接连接,并且基本上是即时消息传递。现在我们已经解决了这个问题,我们需要能够从 Vue 发送和接收。接下来让我们看看。
向 Vue.JS 添加 websocket#
在src文件夹中打开App.vue 。编辑 Javascript,使其看起来像这样:
export default {
name: 'App',
data() {
return {
socket: {},
connectedStatus: 'Not connected!',
message: 'No message yet!'
}
},
async mounted() {
// Calculate the URL for the websocket. If you have a fixed URL, then you can remove all this and simply put in
// ws://your-url-here.com or wss:// for secure websockets.
const socketProtocol = (window.location.protocol === 'https:' ? 'wss:' : 'ws:')
const port = ':3000';
const echoSocketUrl = socketProtocol + '//' + window.location.hostname + port + '/ws'
// Define socket and attach it to our data object
this.socket = await new WebSocket(echoSocketUrl);
// When it opens, console log that it has opened. and send a message to the server to let it know we exist
this.socket.onopen = () => {
console.log('Websocket connected.');
this.connectedStatus = 'Connected';
this.sendMessage(JSON.stringify({"message" : "Hello, server."}));
}
// When we receive a message from the server, we can capture it here in the onmessage event.
this.socket.onmessage = (event) => {
// We can parse the data we know to be JSON, and then check it for data attributes
let parsedMessage = JSON.parse(event.data);
// If those data attributes exist, we can then console log or show data to the user on their web page.
console.log(parsedMessage);
if(typeof parsedMessage.message !== "undefined" && parsedMessage.message == "hello") {
this.message = parsedMessage.message;
console.log('We have received a message from the server!')
}
}
},
methods: {
waitForOpenConnection: function() {
// We use this to measure how many times we have tried to connect to the websocket server
// If it fails, it throws an error.
return new Promise((resolve, reject) => {
const maxNumberOfAttempts = 10
const intervalTime = 200
let currentAttempt = 0
const interval = setInterval(() => {
if (currentAttempt > maxNumberOfAttempts - 1) {
clearInterval(interval)
reject(new Error('Maximum number of attempts exceeded.'));
} else if (this.socket.readyState === this.socket.OPEN) {
clearInterval(interval)
resolve()
}
currentAttempt++
}, intervalTime)
})
},
sendMessage: async function(message) {
// We use a custom send message function, so that we can maintain reliable connection with the
// websocket server.
if (this.socket.readyState !== this.socket.OPEN) {
try {
await this.waitForOpenConnection(this.socket)
this.socket.send(message)
} catch (err) { console.error(err) }
} else {
this.socket.send(message)
}
}
}
}
如何创建 Vue.JS websocket 服务器:细节#
虽然有内联注释,但让我们更详细地看一下。我们首先创建两个方法:
- sendMessage – 这是一个自定义发送消息功能,使用
socket.send()
. 唯一的区别是我们在发送之前测试了一个 websocket 服务器连接,为我们省去了一点麻烦。 - waitForOpenConnection – 这仅由 sendMessage 使用,它设置检查套接字连接的间隔,或引发错误。
将我们的套接字保存为数据
然后,我们使用以下行创建一个新的 websocket 连接,在mounted()
. 这意味着当应用程序安装到浏览器窗口(或加载时)时,我们创建一个新的 websocket 连接,然后data()
通过设置this.socket
新的 websocket 服务器连接将其附加到我们的 .
const socketProtocol = (window.location.protocol === 'https:' ? 'wss:' : 'ws:')
const port = ':3000';
const echoSocketUrl = socketProtocol + '//' + window.location.hostname + port + '/ws'
// Define socket and attach it to our data object
this.socket = await new WebSocket(echoSocketUrl);
这样做的额外好处是我们现在可以跨方法、观察者和所有其他类型的 Vue 功能引用我们的套接字。创建连接后,我们添加两个事件。一种是检查套接字何时打开,另一种是中继消息。
// When it opens, console log that it has opened. and send a message to the server to let it know we exist
this.socket.onopen = () => {
console.log('Websocket connected.');
this.connectedStatus = 'Connected';
this.sendMessage(JSON.stringify({"message" : "Hello, server."}));
}
// When we receive a message from the server, we can capture it here in the onmessage event.
this.socket.onmessage = (event) => {
// We can parse the data we know to be JSON, and then check it for data attributes
let parsedMessage = JSON.parse(event.data);
// If those data attributes exist, we can then console log or show data to the user on their web page.
console.log(parsedMessage);
if(typeof parsedMessage.message !== "undefined" && parsedMessage.message == "hello") {
this.message = parsedMessage.message;
console.log('We have received a message from the server!')
}
}
该onmessage
功能可能是 websocket 创建者最感兴趣的,因为这是处理来自服务器的数据的地方。我们之前创建的消息将到达此事件,我们可以将其显示在页面上。其他数据也可以在这里处理。
由于我还创建了另外两个数据变量message
和connectedStatus
,我们可以在模板中使用它们来显示来自我们的 websocket 服务器的响应:
<template>
<h2>Welcome to Websockets</h2>
<p>You are: </p>
<p>Your message is: </p>
</template>
我们的 websocket 服务器页面
结论#
vue 中的 Websocket 服务器实际上工作得非常优雅。在本教程中,我们已经介绍了所有基础知识。现在您可以继续从您的 websocket 服务器向浏览器发送或接收数据。如果您从 HTTP 切换,websocket 带来的效率意味着您的网站看起来会更快。
不要忘记,在单独的终端窗口中运行,这样npm run serve
你的 websocket 服务器和 Vue.JS 应用程序都在运行。像往常一样,这里有一些有用的链接:node index.mjs