Request Lifecycle

Nest 애플리케이션은 요청 수명 주기라고 하는 시퀀스에 따라 요청을 처리하고 응답을 생성합니다. 미들웨어, 파이프, 가드, 인터셉터를 사용하면 요청 수명 주기 동안 특정 코드가 실행되는 위치를 추적하기가 어려울 수 있으며, 특히 글로벌, 컨트롤러 수준 및 경로 수준 구성 요소가 작용하기 때문에 더욱 그렇습니다. 일반적으로 요청은 미들웨어를 통해 가드로, 인터셉터로, 파이프로, 마지막으로 반환 경로의 인터셉터로(응답이 생성될 때) 다시 흐릅니다.

Middleware

미들웨어는 특정 순서로 실행됩니다. 먼저 Nest는 전역으로 바인딩된 미들웨어(예: app.use로 바인딩된 미들웨어)를 실행한 다음 경로에 따라 결정되는 모듈 바인딩된 미들웨어를 실행합니다. 미들웨어는 바인딩된 순서대로 순차적으로 실행되며, 이는 Express의 미들웨어가 작동하는 방식과 유사합니다. 여러 모듈에 바인딩된 미들웨어의 경우 루트 모듈에 바인딩된 미들웨어가 먼저 실행되고, 그 다음 모듈이 임포트 배열에 추가되는 순서대로 미들웨어가 실행됩니다.

Guards

가드 실행은 글로벌 가드부터 시작하여 컨트롤러 가드, 마지막으로 라우팅 가드로 진행됩니다. 미들웨어와 마찬가지로 가드는 바인딩된 순서대로 실행됩니다. 예를 들어:

@UseGuards(Guard1, Guard2)
@Controller('cats')
export class CatsController {
  constructor(private catsService: CatsService) {}

  @UseGuards(Guard3)
  @Get()
  getCats(): Cats[] {
    return this.catsService.getCats();
  }
}

가드1은 가드2보다 먼저 실행되고 두 가드 모두 가드3보다 먼저 실행됩니다.

힌트:
전역 바인딩과 컨트롤러 또는 로컬 바인딩의 차이점은 가드(또는 다른 컴포넌트)가 바인딩되는 위치에 있습니다. app.useGlobalGuard()를 사용하거나 모듈을 통해 컴포넌트를 제공하는 경우 전역으로 바인딩됩니다. 그렇지 않으면 데코레이터가 컨트롤러 클래스 앞에 오는 경우 컨트롤러에, 데코레이터가 라우트 선언 앞에 오는 경우 라우트에 바인딩됩니다.

Interceptors

인터셉터는 대부분 가드와 동일한 패턴을 따르지만, 한 가지 차이점이 있습니다. 인터셉터가 RxJS Observables를 반환할 때, 관찰 가능 항목은 선입선출 방식으로 해결됩니다. 따라서 인바운드 요청은 표준 전역, 컨트롤러, 경로 수준 해결을 거치지만 요청의 응답 측(즉, 컨트롤러 메서드 핸들러에서 반환된 후)은 경로에서 컨트롤러, 전역으로 해결됩니다. 또한 파이프, 컨트롤러 또는 서비스에서 발생하는 모든 오류는 인터셉터의 catchError 연산자에서 읽을 수 있습니다.

Pipes

파이프는 표준 글로벌에서 컨트롤러로 라우트 바운딩 순서를 따르며, @UsePipes() 매개변수와 관련하여 동일한 선입선출 방식을 따릅니다. 그러나 경로 매개변수 수준에서 여러 개의 파이프를 실행하는 경우 마지막 매개변수에서 첫 번째 매개변수까지 파이프가 있는 순서대로 실행됩니다. 이는 경로 수준 및 컨트롤러 수준 파이프에도 적용됩니다. 예를 들어 다음과 같은 컨트롤러가 있다고 가정해 보겠습니다:

@UsePipes(GeneralValidationPipe)
@Controller('cats')
export class CatsController {
  constructor(private catsService: CatsService) {}

  @UsePipes(RouteSpecificPipe)
  @Patch(':id')
  updateCat(
    @Body() body: UpdateCatDTO,
    @Param() params: UpdateCatParams,
    @Query() query: UpdateCatQuery,
  ) {
    return this.catsService.updateCat(body, params, query);
  }
}

인 경우 쿼리, 매개변수, 본문 객체에 대해 GeneralValidationPipe가 실행된 다음 동일한 순서를 따르는 RouteSpecificPipe로 이동합니다. 매개변수별 파이프가 있는 경우 컨트롤러 및 경로 수준 파이프 다음에 매개변수별 파이프가 실행됩니다(다시 말해서 마지막 매개변수에서 첫 번째 매개변수까지).

Filters

필터는 전역 먼저 해결하지 않는 유일한 컴포넌트입니다. 대신 필터는 가능한 가장 낮은 수준부터 해결되므로 실행은 경로 바인딩 필터부터 시작하여 컨트롤러 수준, 마지막으로 전역 필터로 진행됩니다. 예외는 필터 간에 전달될 수 없으며, 경로 수준 필터가 예외를 잡으면 컨트롤러 또는 전역 수준 필터는 동일한 예외를 잡을 수 없다는 점에 유의하세요. 이와 같은 효과를 얻을 수 있는 유일한 방법은 필터 간에 상속을 사용하는 것입니다.

힌트:
필터는 요청 프로세스 중에 잡히지 않은 예외가 발생하는 경우에만 실행됩니다. 시도/잡기로 잡힌 예외와 같이 잡힌 예외는 예외 필터를 실행하지 않습니다. 잡히지 않은 예외가 발생하면 나머지 수명 주기는 무시되고 요청은 바로 필터로 건너뛰게 됩니다.

요약

일반적으로, request 라이프사이클은 다음과 같은 순서를 가집니다.

  1. Incoming request
  2. Middleware
    • 2.1. Globally bound middleware
    • 2.2. Module bound middleware
  3. Guards
    • 3.1 Global guards
    • 3.2 Controller guards
    • 3.3 Route guards
  4. Interceptors (pre-controller)
    • 4.1 Global interceptors
    • 4.2 Controller interceptors
    • 4.3 Route interceptors
  5. Pipes
    • 5.1 Global pipes
    • 5.2 Controller pipes
    • 5.3 Route pipes
    • 5.4 Route parameter pipes
  6. Controller (method handler)
  7. Service (if exists)
  8. Interceptors (post-request)
    • 8.1 Route interceptor
    • 8.2 Controller interceptor
    • 8.3 Global interceptor
  9. Exception filters
    • 9.1 route
    • 9.2 controller
    • 9.3 global
  10. Server response