Was ist der Fehlerbehandlungsansatz von nestjs (Geschäftslogikfehler vs. HTTP-Fehler)?

Lesezeit: 4 Minuten

Benutzeravatar von Aaron Ullal
Aaron Ullal

Bei der Verwendung von NestJS zum Erstellen von APIs habe ich mich gefragt, wie Fehler/Ausnahmen am besten behandelt werden. Ich habe zwei verschiedene Ansätze gefunden:

  1. Haben Sie individuelle Dienste und Validierungsrohre throw new Error()haben den Controller catch sie und werfen Sie dann die entsprechende Art von HttpException(BadRequestException, ForbiddenException usw..)
  2. Lassen Sie den Controller einfach die Dienst-/Validierungs-Pipe-Methode aufrufen, die für die Handhabung dieses Teils der Geschäftslogik verantwortlich ist, und lösen Sie die entsprechende aus HttpException.

Beide Ansätze haben Vor- und Nachteile:

  1. Dies scheint der richtige Weg zu sein, der Dienst kann jedoch zurückkehren Error Aus verschiedenen Gründen, woher weiß ich vom Controller, welches die entsprechende Art von wäre HttpException zurückgeben?
  2. Sehr flexibel, aber mit Http verwandte Dinge in den Diensten scheinen einfach falsch zu sein.

Ich habe mich gefragt, welches (falls vorhanden) die “nest js” -Methode ist?

Wie gehen Sie mit dieser Angelegenheit um?

Benutzeravatar von Kim Kern
Kim Kern

Nehmen wir an, Ihre Geschäftslogik löst ein aus EntityNotFoundError und Sie möchten es a zuordnen NotFoundException.

Dafür können Sie eine erstellen Interceptor das verwandelt deine Fehler:

@Injectable()
export class NotFoundInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    // next.handle() is an Observable of the controller's result value
    return next.handle()
      .pipe(catchError(error => {
        if (error instanceof EntityNotFoundError) {
          throw new NotFoundException(error.message);
        } else {
          throw error;
        }
      }));
  }
}

Sie können es dann verwenden, indem Sie es hinzufügen @UseInterceptors(NotFoundInterceptor) an die Klasse oder Methoden Ihres Controllers; oder sogar als globaler Abfangjäger für alle Routen. Natürlich können Sie auch mehrere Fehler in einem Interceptor abbilden.

Probieren Sie es darin aus Codesandbox.

  • Beachten Sie, dass das Code-Snippet bereits den neuen Nest v6-Interceptor verwendet. Ein v5-Beispiel finden Sie in der Codesandbox.

    – Kim Kern

    19. März 2019 um 11:43 Uhr


  • Der nestjs-Ausnahmefilter sieht für diesen Job besser geeignet aus docs.nestjs.com/exception-filters

    – Alexandre Morgaut

    12. September 2022 um 10:09 Uhr

Benutzeravatar von Ukpa Uchechi
Ukpa Uchechi

Nest Js bietet einen Ausnahmefilter, der Fehler behandelt, die nicht in der Anwendungsschicht behandelt werden. Daher habe ich ihn so geändert, dass er 500, einen internen Serverfehler, für Ausnahmen zurückgibt, die nicht Http sind. Dann protokollieren Sie die Ausnahme auf dem Server, dann können Sie wissen, was falsch ist, und es beheben.

import 'dotenv/config';
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, Logger } from '@nestjs/common';

@Catch()
export class HttpErrorFilter implements ExceptionFilter {
  private readonly logger : Logger 
  constructor(){
    this.logger = new Logger 
  }
  catch(exception: Error, host: ArgumentsHost): any {
    const ctx = host.switchToHttp();
    const request = ctx.getRequest();
    const response = ctx.getResponse();

    const statusCode = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR
    const message = exception instanceof HttpException ?  exception.message || exception.message?.error: 'Internal server error'

    const devErrorResponse: any = {
      statusCode,
      timestamp: new Date().toISOString(),
      path: request.url,
      method: request.method,
      errorName: exception?.name,
      message: exception?.message
    };

    const prodErrorResponse: any = {
      statusCode,
      message
    };
    this.logger.log( `request method: ${request.method} request url${request.url}`, JSON.stringify(devErrorResponse));
    response.status(statusCode).json( process.env.NODE_ENV === 'development'? devErrorResponse: prodErrorResponse);
  }
}

  • Schöne Umsetzung! Ich denke, Sie können auch die NestJS-Abhängigkeitsinjektionssyntax verwenden, sodass Sie keine private Eigenschaft “Logger” deklarieren und dann instanziieren müssen. Sie können einfach “private readonly logger : Logger” im Konstruktor verwenden und es wird automatisch instanziiert.

    – Marcus Castanho

    6. Januar 2022 um 14:25 Uhr

  • Vielen Dank, notiert wird die Antwort implementieren und aktualisieren.

    – Ukpa Uchechi

    6. Januar 2022 um 14:34 Uhr


  • Zumindest für meinen Anwendungsfall ist dies die beste Antwort.

    – noamtm

    15. Mai 2022 um 13:53 Uhr

  • FYI @MarcusCastanho – es scheint, dass Sie NestJS DI nicht verwenden können, zumindest wenn Sie einen globalen Filter verwenden – weil Sie den Filter selbst instanziieren müssen.

    – noamtm

    15. Mai 2022 um 13:54 Uhr

  • Um die richtige Fehlermeldung zurückzugeben, müssen Sie Folgendes tun: const message = exception instanceof HttpException ? exception.getResponse()?.['message'] ? exception.getResponse()?.['message'] : exception['message'] : 'Internal server error';

    – Lukas Vellido

    9. Juni 2022 um 15:08 Uhr


Möglicherweise möchten Sie Dienste nicht nur an die HTTP-Schnittstelle, sondern auch an GraphQL oder eine andere Schnittstelle binden. Daher ist es besser, Ausnahmen auf Geschäftslogikebene von Diensten in Ausnahmen auf HTTP-Ebene (BadRequestException, ForbiddenException) in Controllern umzuwandeln.

So könnte es im einfachsten Fall aussehen

import { BadRequestException, Injectable } from '@nestjs/common';

@Injectable()
export class HttpHelperService {
  async transformExceptions(action: Promise<any>): Promise<any> {
    try {
      return await action;
    } catch (error) {
      if (error.name === 'QueryFailedError') {
        if (/^duplicate key value violates unique constraint/.test(error.message)) {
          throw new BadRequestException(error.detail);
        } else if (/violates foreign key constraint/.test(error.message)) {
          throw new BadRequestException(error.detail);
        } else {
          throw error;
        }
      } else {
        throw error;
      }
    }
  }
}

und dann

  • Danke Alex. Wie würden Sie den von Ihnen geposteten Code verwenden? Im Steuergerät?

    – Aaron Ullal

    13. August 2018 um 16:07 Uhr

  • Wie haben Sie diesen Dienst implementiert?

    – Lewsmith

    9. Februar 2020 um 16:47 Uhr

Benutzeravatar von Dario Palminio
Dario Palmino

Sie können auch eine Factory oder einen Handler verwenden, um, wenn der Controller die Ausnahme (Fehler oder Domänenfehler) abfängt, diese einer anderen HttpException zuzuordnen.

@Controller('example')
export class ExampleController {

  @Post('make')
  async make(@Res() res, @Body() data: dataDTO): Promise<any> {
   
    try {
      //process result...
       return res.status(HttpStatus.OK).json(result);
    } catch (error) {
      throw AppErrorHandler.createHttpException(error); //<---here is the error type mapping
    };
  };

};

1441830cookie-checkWas ist der Fehlerbehandlungsansatz von nestjs (Geschäftslogikfehler vs. HTTP-Fehler)?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy