[英]send a websocket message in a route, Express.js
假設我們有一個充滿商店的市場。 我正在為店主創建一個特定頁面localhost:3000/livePurchases/:storeId
來監控他們何時獲得新購買的實時通知。
alert('you received a new purchase')
應在購買商品時由 WebSocket 觸發。
我需要在我的 express 服務器上設置 WebSocket,以便可以在我的代碼中與設置 websocket 服務器的位置不同的地方觸發 websocket。 但我不明白如何做到這一點。
在成功購買商品后,客戶的瀏覽器將請求路由/newPurchase/:storeId
。 websocket 應在"/newPurchase/:storeId"
(后端)的路由代碼內向"/livePurchases/:storeId"
(前端)上的 websocket 發送一條消息,店主可以在其中監控實時購買。
app.js
const express = require("express");
module.exports = (config) => {
const app = express();
app.post("/newPurchase/:storeId", (req, res, next) => {
const { storeId } = req.params;
// trigger websocket message to `localhost:3000/livePurchases/:storeId`
// when client requests this route
});
return app;
};
但是 app.js 是從另一個腳本www.js
導出和運行的。 在實際場景中,這是在運行應用程序之前連接數據庫:
www.js
const app = require("../server/app")();
const port = process.env.PORT || "4000";
app.set("port", port);
app
.listen(port)
.on("listening", () =>
console.log("info", `HTTP server listening on port ${port}`)
);
module.exports = app;
這意味着需要在www.js
中設置 web 套接字服務器。
下面是我從本教程中獲得的通知服務,它似乎試圖解決我遇到的問題,但沒有解釋如何實現它。 它是一個處理 websocket 的 class。
NotifierService.js
const url = require("url");
const { Server } = require("ws");
class NotifierService {
constructor() {
this.connections = new Map();
}
connect(server) {
this.server = new Server({ noServer: true });
this.interval = setInterval(this.checkAll.bind(this), 10000);
this.server.on("close", this.close.bind(this));
this.server.on("connection", this.add.bind(this));
server.on("upgrade", (request, socket, head) => {
console.log("ws upgrade");
const id = url.parse(request.url, true).query.storeId;
if (id) {
this.server.handleUpgrade(request, socket, head, (ws) =>
this.server.emit("connection", id, ws)
);
} else {
socket.destroy();
}
});
}
add(id, socket) {
console.log("ws add");
socket.isAlive = true;
socket.on("pong", () => (socket.isAlive = true));
socket.on("close", this.remove.bind(this, id));
this.connections.set(id, socket);
}
send(id, message) {
console.log("ws sending message");
const connection = this.connections.get(id);
connection.send(JSON.stringify(message));
}
broadcast(message) {
console.log("ws broadcast");
this.connections.forEach((connection) =>
connection.send(JSON.stringify(message))
);
}
isAlive(id) {
return !!this.connections.get(id);
}
checkAll() {
this.connections.forEach((connection) => {
if (!connection.isAlive) {
return connection.terminate();
}
connection.isAlive = false;
connection.ping("");
});
}
remove(id) {
this.connections.delete(id);
}
close() {
clearInterval(this.interval);
}
}
module.exports = NotifierService;
我在 www.js 中添加了帶有NotifierService
的www.js
服務器
www.js with websockets added
const app = require("../server/app")();
const NotifierService = require("../server/NotifierService.js");
const notifier = new NotifierService();
const http = require("http");
const server = http.createServer(app);
notifier.connect(server);
const port = process.env.PORT || "4000";
app.set("port", port);
server
.listen(port)
.on("listening", () =>
console.log("info", `HTTP server listening on port ${port}`)
);
module.exports = app;
但是現在如何從后端app.js
中的/newPurchase
路由發送 websocket 消息? 如果我在app.js
中創建一個新的NotifierService
實例,以便在/newPurchase
路由中使用notifierService.send
方法,那么新的NotifierService
實例將無法訪問 websocket 連接,因為它與一項在www.js
上發起。
前端:
App.js
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import LiveStorePurchases from "./LiveStorePurchases";
function App(props) {
return (
<div className="App">
<Router>
<Switch>
<Route exact path="/livePurchases/:storeId">
<LiveStorePurchases />
</Route>
</Switch>
</Router>
</div>
);
}
export default App;
LivePurchaseServer.js
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
export default function LiveStorePurchases() {
let { storeId } = useParams();
const URL = "ws://127.0.0.1:4000?storeId=" + storeId;
const [ws, setWs] = useState(new WebSocket(URL));
useEffect(() => {
ws.onopen = (e) => {
newFunction(e);
function newFunction(e) {
alert("WebSocket Connected");
}
};
ws.onmessage = (e) => {
const message = e.data;
alert(message);
};
return () => {
ws.onclose = () => {
alert("WebSocket Disconnected");
setWs(new WebSocket(URL));
};
};
}, [ws.onmessage, ws.onopen, ws.onclose, ws, URL]);
return (
<div
style={{
color: "red",
fontSize: "4rem",
}}
>
store: {storeId}
</div>
);
}
app.js
:
我能夠將 websocket 實例移動到app.js
而不是www.js
。 然后我只是將該實例傳遞給其他路線。
const express = require("express");
const NotifierService = require("../server/NotifierService.js");
const notifier = new NotifierService();
const http = require("http");
const routes = require("./routes");
module.exports = (config) => {
const app = express();
const server = http.createServer(app); // websocket created
notifier.connect(server); // and connected here in app.js
// I moved POST /newPurchase to routes.js in order
// to demonstrate how the notifier instance can be
// passed around to different routes
app.use(routes(notifier));
return server;
};
routes.js
:
我創建了一個路由文件routes.js
以表明您可以移動通知程序實例並從任何路由調用它。
const express = require("express");
const router = express.Router();
// I moved "/newPurchase/:id" to this routes.js file to show that
// I could move the notifier instance around.
module.exports = (webSocketNotifier) => {
router.post("/newPurchase/:id", (req, res, next) => {
webSocketNotifier.send(req.params.id, "purchase made");
res.status(200).send();
});
return router;
};
www.js
:
const server = require("../server/app")();
const port = process.env.PORT || "4000";
server
.listen(port)
.on("listening", () =>
console.log("info", `HTTP server listening on port ${port}`)
);
module.exports = server;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.