如何将数据从 WebSocket 连接转发到 Express 中的服务器发送事件?

问题描述 投票:0回答:1

当客户端请求 Express.js / Node.js 服务器上的端点时,服务器会连接到外部 WebSockets 端点,并接收多条消息中的数据。我希望能够将通过该连接接收到的数据作为服务器发送事件转发到客户端。

所以我需要的连接如下所示:

Client
<-服务器发送事件->
Node/Express server
<-WebSocket->
External server

socket连接被封装在一个简单的类中:

class SocketClient {
  private socket: WebSocket;

  constructor() {
    this.socket = new WebSocket("ws://example.com");
    this.socket.send("something");
    socket.addEventListener("message", (event) => {
      console.log("Message from server ", event.data);
    });
  }
}

,在 Express 方面是一个标准 HTTP 端点,我想在其中使用

Node 
write
的标准 end
Response
方法:

const app = express();

app.get('/', (req, res) => {
  const client = new SocketClient();

  while (await client.isDataAvailable()) {
    res.write(await client.getNextDataChunk());
  }
  res.end();
});

我正在努力将数据从一个异步连接转发到另一个异步连接。在上面的代码中,这意味着在

isDataAvailable
上实现
getNextDataChunk
SocketClient
方法,或者其他可以实现类似结果的方法。

node.js express websocket backend server-sent-events
1个回答
0
投票

我已经通过将 WebSocket 消息包装在 Promises 中解决了这个问题,这些消息仅在连接打开时或收到来自套接字连接的最后一条消息时解析(可以更改以满足您的需求,例如在连接关闭时解析) :

class SocketClient {
    private socket: WebSocket;

    // Important: only resolve promise when connection opened
    public async connectToSocket() {
        return new Promise<void>((resolve, reject) => {
            const socket = new WebSocket("wss://example.com");
            this.socket = socket;

            socket.onopen = (event) => {
                resolve();
            }
        });
    }

    public async getAsyncData(callback: (chunk: string | Buffer | Uint8Array) => Promise<void>): Promise<void> {
        // Send anything from client side as needed
        this.socket.send("...");

        // Listen to responses and asyncronously call the callback
        this.socket?.addEventListener("message", async (event) => {
            if (event.data) {
                await callback(event.data);
            }
        });

        await this.finishGettingData();
    }

    // Importantly, this only resolves after the last message
    private async finishGettingData() {
        return new Promise<boolean>((resolve) => {
            (this.socket as WebSocket).addEventListener("message", (event) => {
                // Check for end message, depends on your specific case also
                // For this example, checking for message content
                if (event.data === "Final message") {
                    resolve(true);
                }
            });
        });
    }
}

const app = express();

app.get('/', async (req, res) => {
    const client = new SocketClient();

    await client.connectToSocket();

    // This will only resolve when ending message is received.
    await client.getAsyncData(async (chunk) => {
        console.log("Writing a chunk to client, size", chunk.length);
        res.write(chunk);
    });
    res.end();
});
© www.soinside.com 2019 - 2024. All rights reserved.