#Websocket-Filter doesn't work as intended.

30 messages · Page 1 of 1 (latest)

neon topaz
#

Hey guys, I implemented a global filter for websocket exceptions and it seems like the filter does kind of work as the errors are caught and don't break my backend anymore.

This is my filter and how I apply it:

@Catch(WsException)
export class GlobalWsExceptionFilter extends BaseWsExceptionFilter {
  constructor() {
    super();
  }

  catch(exception: WsException, host: any) {
    const client = host.switchToWs().getClient();

    // Handle the WsException and send an error message to the client
    client.emit('error', exception.getError());

    // Optionally, you can log the error or perform additional actions
    console.log("Calling Exception Filter")
    console.log(exception.message)

    // Call the super method to finalize the exception handling
    super.catch(exception, host);
  }
}```

main.ts:
```async function bootstrap() {
  const app = await NestFactory.create(AppModule)
  app.enableCors({ origin: "http://localhost:3000", credentials: true })
  app.use(cookieParser())
  // app.useGlobalPipes(new CustomValidationPipe())
  // app.useGlobalFilters(new CustomExceptionFilter())
  app.useGlobalFilters(new HttpExceptionFilter(), new GlobalWsExceptionFilter())
  await app.listen(8080)
}
bootstrap()```

I then on purpose throw the WsException in this handler: 

@SubscribeMessage("startGame")
async handleStartGame(@ConnectedSocket() client: Socket, @MessageBody(new ValidationPipe()) startGameDto: StartGameDto) {
const lobby: PopulatedLobbyDocument = await this.lobbyService.findById(startGameDto.lobbyId)

if (!lobby) {
  console.log("Throwing not found exception")
  throw new WsException(errorMessagesInternationalized.lobbyNotFound)
}

return this.gameService.createGame(lobby)

}```

The exception seems to be thrown, as the print-command in the if-clause is executed but caught as it doesn't break my backend. It is confusing though as the print-commands in the filter aren't executed.

hallow crane
#

Globally bound enhancers don't affect websockets. You need bind then to the gateway or method directly

neon topaz
#

via the useFilters() decorator?

hallow crane
#

Yep

neon topaz
#

Now the backend crashes again, when a error is thrown:

Throwing not found exception ##THIS IS MY PRINT COMMAND##
Error: Unhandled error. ('errors.lobby.lobbyNotFound')
at new NodeError (node:internal/errors:405:5)
at Socket.emit (node:events:500:17)
at Socket.emit (C:\Users\Niklas Patscheck\QuickQs\QCore\node_modules@nestjs\platform-socket.io\node_modules\socket.io\lib\socket.js:142:10)
at GlobalWsExceptionFilter.catch (C:\Users\Niklas Patscheck\QuickQs\QCore\src\shared\filters\global-ws-exception.filter.ts:16:12)
at WsExceptionsHandler.invokeCustomFilters (C:\Users\Niklas Patscheck\QuickQs\QCore\node_modules@nestjs\websockets\exceptions\ws-exceptions-handler.js:33:26)
at WsExceptionsHandler.handle (C:\Users\Niklas Patscheck\QuickQs\QCore\node_modules@nestjs\websockets\exceptions\ws-exceptions-handler.js:18:18)
at WsProxy.handleError (C:\Users\Niklas Patscheck\QuickQs\QCore\node_modules@nestjs\websockets\context\ws-proxy.js:28:27)
at GameGateway.<anonymous> (C:\Users\Niklas Patscheck\QuickQs\QCore\node_modules@nestjs\websockets\context\ws-proxy.js:21:22)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at WebSocketsController.pickResult (C:\Users\Niklas Patscheck\QuickQs\QCore\node_modules@nestjs\websockets\web-sockets-controller.js:96:24)

#

I passed thge filter like this:

@UseFilters(GlobalWsExceptionFilter)
@WebSocketGateway({ namespace: "game" })
export class GameGateway implements OnGatewayInit {

hallow crane
#
  1. is WsException imported from @nestjs/websockets
  2. is the server fully crashing, or is Nest just printing the exception?
neon topaz
#
  1. Yes, it is
  2. I think so, yes, I am not able to connect a websocket anymore
hallow crane
#

Very interesting. That shouldn't be crashing from what I can see

#

It's like the client.emit('error', 'errors.lobby.lobbyNotFound') is causing an issue for whatever reason. If you change the emit from emit('error',...) to emit('exception', ...) does this still happen?

neon topaz
#

it works

#

WHY??

neon topaz
#

the socket doesn't get a response though as intended

hallow crane
hallow crane
neon topaz
#

okay, thank you! Postman isn't capable of that I suppose?

hallow crane
#

You should be able to add an exception event listener

hallow crane
neon topaz
#

thanks again!

#

Another question related to that

#

I validate my dtos through nests validation pipe

#

If this throws an error that's a http-format error, right?

#

So I need to catch that seperately?

hallow crane
#

Yes, it's an HttpException, you'd need to catch that and turn it into a WsException or just bind some sort HttpException handler

neon topaz
#

I'll just bind the same exception filter that I use globally for all of my controllers👍

neon topaz
neon topaz
#

New question, old topic:

my filter: ```import { ArgumentsHost, Catch, HttpException, Injectable } from "@nestjs/common"
import { BaseWsExceptionFilter } from "@nestjs/websockets/exceptions"
import { WsException } from "@nestjs/websockets"

@Injectable()
@Catch()
export class GlobalWsExceptionFilter extends BaseWsExceptionFilter {
constructor() {
super()
}

catch(exception: WsException | HttpException, host: ArgumentsHost) {
if (exception instanceof WsException) {
const client = host.switchToWs().getClient()

  // Handle the WsException and send an error message to the client
  //client.emit("exception", exception.getError())

  //console.log("Calling Exception Filter")
  //console.log(exception.message)

  // Call the super method to finalize the exception handling
  super.catch(exception, host)
}

}
}```

#

The BaseWsExceptionFilter: ```import { ArgumentsHost, Logger, WsExceptionFilter } from '@nestjs/common';
import { isObject } from '@nestjs/common/utils/shared.utils';
import { MESSAGES } from '@nestjs/core/constants';
import { WsException } from '../errors/ws-exception';

/**

  • @publicApi
    */
    export class BaseWsExceptionFilter<TError = any>
    implements WsExceptionFilter<TError>
    {
    private static readonly logger = new Logger('WsExceptionsHandler');

public catch(exception: TError, host: ArgumentsHost) {
const client = host.switchToWs().getClient();
this.handleError(client, exception);
}

public handleError<TClient extends { emit: Function }>(
client: TClient,
exception: TError,
) {
if (!(exception instanceof WsException)) {
return this.handleUnknownError(exception, client);
}

const status = 'error';
const result = exception.getError();
const message = isObject(result)
  ? result
  : {
      status,
      message: result,
    };

client.emit('exception', message);

}

public handleUnknownError<TClient extends { emit: Function }>(
exception: TError,
client: TClient,
) {
const status = 'error';
client.emit('exception', {
status,
message: MESSAGES.UNKNOWN_EXCEPTION_MESSAGE,
});

if (this.isExceptionObject(exception)) {
  return BaseWsExceptionFilter.logger.error(
    exception.message,
    exception.stack,
  );
}
return BaseWsExceptionFilter.logger.error(exception);

}

public isExceptionObject(err: any): err is Error {
return isObject(err) && !!(err as Error).message;
}
}```