WebSockets handshake not working with NestJS when bootstrapping with express (multiple servers)

Viewed 878

Our NestJs server used to handle websockets handshakes perfectly over HTTP. But then we added HTTPS support, and we did it using the multiple servers technique as described here: https://docs.nestjs.com/faq/multiple-servers

After doing so, websockets handshakes (upgrade requests) have stopped working.

The NestJs bootstrapping we had that had web sockets working was like this:

const app = await NestFactory.create(AppModule);
const webSocketAdapter = new WebSocketAdapter(app);
app.useWebSocketAdapter(webSocketAdapter);

[...] // We initialize express sessions and passport here.

await app.init();
await app.listen(80);

To support both HTTP and HTTPS at the same time, we followed instructions as indicated on https://docs.nestjs.com/faq/multiple-servers and changed the bootstrapping as follows:

const server = express();
const app = await NestFactory.create(AppModule, new ExpressAdapter(server));
const webSocketAdapter = new WebSocketAdapter(app);
app.useWebSocketAdapter(webSocketAdapter);

[...] // We initialize express sessions and passport here.

await app.init();

http.createServer(server).listen(80);
const httpsConfiguration = [...] // Nothing meaningful here. We load PEM files and put them in there.
https.createServer(httpsConfiguration, server).listen(443);

After that change, our web sockets stopped working. I verified in our WebSocketAdapter if the verifyClient() function is getting called. It is not any longer. So it seems like NestJs doesn't seem to process the request as a websocket upgrade request any longer.

In the browser, the console displays the following error message:

myScript.js:123 WebSocket connection to 'ws://localhost/api/v1/mysubpath' failed: Error during WebSocket handshake: Unexpected response code: 200

I have been trying to figure out what is going wrong by tracing in the NestJs code, but it's not a trivial task at all.

Has anyone have an idea as to why websockets are no longer working?

EDIT:

After investigating further, it seems like the WsAdapter can't properly initialize the websocket server if we supply it the Nest application when the Nest application is initialized with an Express adapter. So instead we provide to the WebSocket adapter the http server instance.

However, we are then stuck to not being able to serve websockets on HTTP and HTTPS at the same time. We can supply only one server to the websocket adapter, and only one websocket adapter can be supplied to the nest application. So we could not figure out a way to get the adapter or Nest application to support web sockets for both HTTP and HTTPS simultaneously.

Our code now looks like this:

const server = express();
const app = await NestFactory.create(AppModule, new ExpressAdapter(server));

const httpServer = http.createServer(server);
const httpsConfiguration = [...]
const httpsServer = https.createServer(httpsConfiguration, server)

const webSocketAdapter = new WebSocketAdapter(httpServer); // Here we can only supply one server. 
app.useWebSocketAdapter(webSocketAdapter); // Here we can only supply one adapter.

[...] // We initialize express sessions and passport here.

await app.init();

httpServer.listen(80);
httpsServer.listen(443);
0 Answers
Related