인터셉터
Coddy Node.js 여정의 TypeScript와 NestJS 섹션에 포함된 레슨. 24개 중 23번째.
각 핸들러를 일일이 수정하지 않고도 모든 응답에 처리 시간이 표시되게 하고 싶습니다. 인터셉터는 핸들러를 감쌉니다. next.handle() 앞에 있는 코드는 핸들러 실행 전에 실행되고, next.handle()가 반환하는 값에 연결된 코드는 핸들러 실행 후에 실행됩니다.
intercept(context: ExecutionContext, next: CallHandler) {
console.log('before');
return next.handle().pipe(
tap(() => console.log('after')),
);
}next.handle()은 핸들러의 결과를 RxJS 옵저버블로 제공하며, 이 값은 나중에 도착합니다. .pipe(tap(...))은 값이 도착할 때 함수를 실행하며, Nest가 값을 보내기 전에 실행됩니다. 여기서 pipe는 Nest의 유효성 검사 파이프와는 아무 관련이 없습니다. 가드는 모든 인터셉터보다 먼저 실행되므로 가드가 거부한 요청은 인터셉터에 도달하지 않습니다. 파이프 처리된 옵저버블을 반환하세요. Nest는 그 안에 담긴 값을 보냅니다. context.switchToHttp().getResponse()는 res를 제공하며, setHeader로 헤더를 추가할 수 있습니다.
app.useGlobalInterceptors(...)는 모든 경로에 인터셉터를 적용하고, @UseInterceptors(...)는 하나의 컨트롤러에 적용합니다.
챌린지
쉬움‘실행’을 누르면 src/main.ts를 사용해 트래커가 다시 시작됩니다. 별도의 연습 파일은 트리 안에 그대로 두어도 됩니다. 이 서버는 해당 파일들을 시작하지 않습니다.
클라이언트와 자체 모니터링 시스템은 각 요청이 처리되는 데 걸린 시간을 알고 싶어 합니다. 어떤 경로도 건드리지 않고 모든 성공 응답에 응답 헤더 X-Response-Time을 추가하세요.
src/common/response-time.interceptor.ts를 여세요.ResponseTimeInterceptor의intercept메서드에서 먼저 현재 시각을Date.now()로 기록하세요.intercept의 맨 위에 있는 코드는 경로의 메서드보다 먼저 실행됩니다.context.switchToHttp().getResponse()를 사용해 Express의res를 가져오세요.next.handle()은 경로의 메서드를 실행하고 그 결과를 RxJS 옵저버블로 반환합니다. 옵저버블은 나중에 도착하는 값입니다. 계속해서 이 값을 반환하되, 이미rxjs에서 가져온tap을 옵저버블의.pipe()메서드로 거쳐 전달하세요.tap에 전달하는 함수는 결과가 도착했을 때 Nest가 결과를 보내기 전에 실행됩니다. 그 함수에서res.setHeader를 호출해X-Response-Time을 설정하세요. 값은 시간을 기록한 뒤 지난 밀리초에ms를 붙인 것으로, 예를 들어3ms와 같습니다. (RxJS의.pipe()는 3장의 유효성 검사 파이프와 관계가 없습니다. 옵저버블에 단계를 연결합니다.)src/main.ts에서 파이프와 필터 옆에app.useGlobalInterceptors(...)를 사용해 새ResponseTimeInterceptor를 전달하고, 인터셉터를 앱 전체에 등록하세요.- 응답 본문은 변경되면 안 됩니다.
GET /tasks는 계속{ "items": [...], "page": 1, "total": 3, "pages": 2 }를 반환해야 합니다.
직접 해 보기: GET /tasks를 보내고 응답의 Headers 탭을 여세요. X-Response-Time이 표시되며, 값은 0ms 또는 2ms와 같은 형식입니다. GET /stats에도 이 헤더가 있으며, x-api-key: tasks-key-123 헤더와 함께 보낸 { "title": "Buy milk" } POST 요청에도 표시됩니다. 그런 다음 키 없이 해당 POST 요청을 보내 보세요. 응답은 403이며 X-Response-Time은 없습니다. Nest는 인터셉터보다 가드를 먼저 실행하므로, 가드가 인터셉터가 시작되기 전에 요청을 거부했습니다. 경로 안에서 오류가 발생한 경우에도 헤더가 생략됩니다. 결과가 도착했을 때만 tap이 실행되기 때문입니다.
직접 해보기
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable, tap } from 'rxjs';
@Injectable()
export class ResponseTimeInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
// 시간을 기록하고 핸들러를 실행한 다음 X-Response-Time을 설정합니다.
return next.handle();
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
TypeScript와 NestJS의 모든 레슨
직접 연습해 보세요: Express 플레이그라운드