为 Express 定义 Websocket 路由 [英] Defining Websocket routes for Express

查看:25
本文介绍了为 Express 定义 Websocket 路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在 ExpressJS 应用程序中使用 ws 库为 Websockets 定义路由?将两层并行设置非常容易,但是 Websocket 层将无法从 ExpressJS 中间件(例如身份验证)中受益.我能找到的唯一实现是 express-ws,由于未启动而存在严重问题迄今为止,并且严重依赖于monkeypatching 才能工作.

How can I define routes for Websockets using the ws library within an ExpressJS app? It's very easy to set it up the two layers in parallel, but the Websocket layer will not be able to benefit from ExpressJS middlewares (such as authentication). The only implementation I could find was express-ws, which is severely buggy due to not being up to date, and heavily relies on monkeypatching in order to work.

推荐答案

部分修改自此 答案.修改您的入口文件以包含以下内容:

Partially modified from this answer. Modify your entry file to include this:

/* index.ts */
import http from 'http';
import express from 'express';
import exampleRouter from './exampleRouter';

// set up express and create a http server listen for websocket requests on the same port
const app = express();
const server = http.createServer(app);

// listen for websocket requests, which are simple HTTP GET requests with an upgrade header
// NOTE: this must occur BEFORE other middleware is set up if you want the additional ws.handled functionality to close unhandled requests
server.on('upgrade', (req: Request & { ws: { socket: Socket, head: Buffer, handled: Boolean } }, socket: Socket, head: Buffer) => {
  // create a dummy response to pass the request into express
  const res = new http.ServerResponse(req);
  // assign socket and head to a new field in the request object
  // optional **handled** field lets us know if there a route processed the websocket request, else we terminate it later on
  req.ws = { socket, head, handled: false };
  // have Express process the request
  app(req, res);
});

/* whatever Express middlewares you want here, such as authentication */
app.use('/example', exampleRouter);

// set up a middleware to destroy unhandled websocket requests and returns a 403
// NOTE: this must occur AFTER your other middlewares but BEFORE the server starts listening for requests
app.use((req: Request & { ws?: { socket: Socket, head: Buffer, handled: Boolean } }, res: Response, next: NextFunction): void => {
  if (req.ws && req.ws.handled === false) {
    req.ws.socket.destroy();
    res.status(404).json('404: Websocket route not found');
  }
  next();
});

const port = process.env.PORT || 8080;
server.listen(port);

具有 ws 功能的 Express Router 示例,但可以提取逻辑以用于一次性使用

Example of a Express Router with ws functionality, but the logic can be extracted to be used for one-offs

/* RouterWithWebSockets.ts */
// this is just a simple abstraction implementation so the you can set up multiple ws routes with the same router
// without having to rewrite the WSS code or monkeypatch the function into the Express Router directly
import express from 'express';
import { WebSocketServer, WebSocket } from 'ws';

class RouterWithWebSockets {
  router;

  constructor(router = express.Router()) {
    this.router = router;
  }

  ws = (path: string, callback: (ws: WebSocket) => void, ...middleware: any): void => {
    // set up a new WSS with the provided path/route to handle websockets
    const wss = new WebSocketServer({
      noServer: true,
      path,
    });

    this.router.get(path, ...middleware, (req: any, res, next) => {
      // just an extra check to deny upgrade requests if the path/route does not match
      // you can process this route as a regular HTTP GET request if it's not a websocket upgrade request by replacing the next()
      if (!req.headers.upgrade || path !== req.url) {
        next();
      } else {
        req.ws.handled = true;
        wss.handleUpgrade(req, req.ws.socket, req.ws.head, (ws: WebSocket) => {
          callback(ws);
        });
      }
    });
  };
}

export default RouterWithWebSockets;

最后,这是一个带有 Websocket 路由的示例路由器

Finally, here is an example router with the Websocket routes

/* exampleRouter.ts */

const routerWithWebSockets = new RouterWithWebSockets();

routerWithWebSockets.router.get('/nonWSRoute', doSomething1); // processed as HTTP GET request

routerWithWebSockets.router.get('/wsRoute1', doSomething2); // processed as HTTP GET request

routerWithWebSockets.ws('/wsRoute1', (ws) => doSomethingWithWS1); // processed as Websocket upgrade request

routerWithWebSockets.ws('/wsRoute2', (ws) => doSomethingWithWS2); // processed as Websocket upgrade request

export default routerWithWebSockets.router;

这篇关于为 Express 定义 Websocket 路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆