ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๋ฐ˜์‘ํ˜•

๐ŸŒ€ NestJS Interceptor ์™„์ „ ๊ฐ€์ด๋“œ – ์‘๋‹ต ๋ณ€ํ˜•, ๋กœ๊น…, ์บ์‹ฑ, ์„ฑ๋Šฅ ์ถ”์ ๊นŒ์ง€


NestJS์—์„œ **Interceptor(์ธํ„ฐ์…‰ํ„ฐ)**๋Š” Controller ๋ฉ”์„œ๋“œ ์ „ํ›„๋กœ ์‹คํ–‰๋˜์–ด, ์‘๋‹ต์„ ๊ฐ€๊ณตํ•˜๊ฑฐ๋‚˜ ์š”์ฒญ์„ ๊ฐ์‹ธ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
์ด ๊ธ€์€ NestJS ๊ณต์‹ ๋ฌธ์„œ Interceptors๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ๊ธ€ ๋ฒˆ์—ญ + ์‹ค์ „ ์ค‘์‹ฌ ํ•ด์„ค๋กœ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ’ก Interceptor๋Š” NestJS์˜ "Aspect-Oriented Programming(AOP)"์„ ์‹คํ˜„ํ•˜๋Š” ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.


โœ… Interceptor๋Š” ์–ธ์ œ ์‚ฌ์šฉํ•˜๋‚˜์š”?

  • ์‘๋‹ต ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ๋ณ€๊ฒฝ
  • ์š”์ฒญ/์‘๋‹ต ๋กœ๊น…
  • ์š”์ฒญ ์‹œ๊ฐ„ ์ธก์ • (Performance)
  • ๊ฒฐ๊ณผ ์บ์‹ฑ
  • ์—๋Ÿฌ ๋ฆฌํฌํŠธ ๊ฐ์‹ธ๊ธฐ (try/catch ๋Œ€์‹ )

1๏ธโƒฃ Interceptor ๊ธฐ๋ณธ ๊ตฌ์กฐ

import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const now = Date.now();
    return next.handle().pipe(
      tap(() => console.log(`โฑ ์ฒ˜๋ฆฌ ์‹œ๊ฐ„: ${Date.now() - now}ms`)),
    );
  }
}

๊ตฌ์กฐ ์„ค๋ช…

  • intercept()๋Š” ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑ„๋Š” ๋ฉ”์„œ๋“œ
  • next.handle()์€ ์‹ค์ œ ํ•ธ๋“ค๋Ÿฌ ์‹คํ–‰
  • tap()์€ ์‘๋‹ต์ด ์™„๋ฃŒ๋œ ํ›„ ํ›„์ฒ˜๋ฆฌ

2๏ธโƒฃ ๋ผ์šฐํŠธ์— Interceptor ์ ์šฉํ•˜๊ธฐ

@UseInterceptors(LoggingInterceptor)
@Get()
getData() {
  return { message: 'Hello Interceptor!' };
}

@UseInterceptors() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ํŠน์ • ์ปจํŠธ๋กค๋Ÿฌ/๋ผ์šฐํŠธ์— ์ธํ„ฐ์…‰ํ„ฐ ์ ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.


๋ฐ˜์‘ํ˜•

์ด ์ง€์ ์€ ์‹ค๋ฌด ์‘๋‹ต ๊ฐ€๊ณต ๋ฐ ๋กœ๊น… ์˜ˆ์ œ๊ฐ€ ๋‚˜์˜ค๋Š” ๊ตฌ๊ฐ„์œผ๋กœ ์• ๋“œ์„ผ์Šค ๊ด‘๊ณ  ์‚ฝ์ž… ์ตœ์  ์œ„์น˜์ž…๋‹ˆ๋‹ค.

<ins class="adsbygoogle"
     style="display:block"
     data-ad-client="ca-pub-XXXXXXX"
     data-ad-slot="YYYYYYY"
     data-ad-format="auto"
     data-full-width-responsive="true"></ins>

3๏ธโƒฃ ์‘๋‹ต ๋ฐ์ดํ„ฐ ๊ฐ€๊ณต Interceptor ์˜ˆ์ œ

@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, ApiResponse<T>> {
  intercept(context: ExecutionContext, next: CallHandler): Observable<ApiResponse<T>> {
    return next.handle().pipe(
      map(data => ({
        success: true,
        data,
        timestamp: new Date().toISOString(),
      })),
    );
  }
}

interface ApiResponse<T> {
  success: boolean;
  data: T;
  timestamp: string;
}

์ปจํŠธ๋กค๋Ÿฌ์—์„œ returnํ•œ ์›์‹œ ๋ฐ์ดํ„ฐ๊ฐ€, ๊ฐ€๊ณต๋œ JSON ํ˜•ํƒœ๋กœ ์ž๋™ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.


4๏ธโƒฃ ์ „์—ญ Interceptor ๋“ฑ๋ก

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalInterceptors(new TransformInterceptor());
  await app.listen(3000);
}

์ „์—ญ ๋“ฑ๋ก์„ ํ†ตํ•ด ๋ชจ๋“  ๋ผ์šฐํŠธ์—์„œ ๊ณตํ†ต๋œ ์‘๋‹ต ๊ตฌ์กฐ ์œ ์ง€๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.


5๏ธโƒฃ ์บ์‹ฑ ์ธํ„ฐ์…‰ํ„ฐ (์‹ค๋ฌด ์˜ˆ์‹œ)

@Injectable()
export class CacheInterceptor implements NestInterceptor {
  private cache = new Map<string, any>();

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const key = context.switchToHttp().getRequest().url;
    if (this.cache.has(key)) {
      return of(this.cache.get(key));
    }

    return next.handle().pipe(
      tap(data => this.cache.set(key, data)),
    );
  }
}

์‹ค๋ฌด์—์„œ Redis์™€ ์—ฐ๋™ํ•˜์—ฌ ๊ณ ๋„ํ™”๋œ ์บ์‹œ ์‹œ์Šคํ…œ๋„ ๊ตฌํ˜„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.


6๏ธโƒฃ Error ๊ฐ์‹ธ๊ธฐ (์‹คํ–‰ ๊ฒฐ๊ณผ Wrapper)

@Injectable()
export class ErrorWrapperInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      catchError(err => {
        return throwError(() => new HttpException({
          success: false,
          error: err.message || '์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜',
        }, err.status || 500));
      }),
    );
  }
}

๐Ÿง  Interceptor vs Middleware vs Guard vs Pipe

ํ•ญ๋ชฉ ์‹œ์  ์—ญํ• 

Middleware Controller ์ง„์ž… ์ „ ์š”์ฒญ ๋กœ๊น…, ์ฟ ํ‚ค ํŒŒ์‹ฑ ๋“ฑ
Guard ๋ผ์šฐํŠธ ์ง„์ž… ์ „ ์ธ์ฆ/์ธ๊ฐ€
Pipe ํ•ธ๋“ค๋Ÿฌ ์‹คํ–‰ ์ „ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ, ํƒ€์ž… ๋ณ€ํ™˜
Interceptor ์‹คํ–‰ ์ „/ํ›„ ์‘๋‹ต ๊ฐ€๊ณต, ๋กœ๊น…, ์บ์‹ฑ

๐Ÿ”š ๋งˆ๋ฌด๋ฆฌ ์š”์•ฝ

  • Interceptor๋Š” ์‘๋‹ต ์ฒ˜๋ฆฌ, ๋กœ๊น…, ๋ณ€ํ™˜, ์บ์‹ฑ ๋“ฑ ํ›„์ฒ˜๋ฆฌ์— ์ตœ์ ํ™”๋œ ๋„๊ตฌ
  • CallHandler.handle()์€ Observable ๊ธฐ๋ฐ˜ → RxJS ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ์‹ค๋ฌด์—์„œ TransformInterceptor, ErrorInterceptor, CacheInterceptor๋Š” ํ•„์ˆ˜ ๋„์ž… ์š”์†Œ

 

NestJS Interceptor,NestJS ์‘๋‹ต ๊ฐ€๊ณต,NestJS ์‘๋‹ต ํฌ๋งท,NestJS ๋กœ๊น… Interceptor,NestJS TransformInterceptor,NestJS ์ „์—ญ ์ธํ„ฐ์…‰ํ„ฐ,NestJS ์บ์‹œ ์ธํ„ฐ์…‰ํ„ฐ,NestJS Error ์ฒ˜๋ฆฌ,NestJS ์„ฑ๋Šฅ์ธก์ •,NestJS ๊ตฌ์กฐํ™” ์‘๋‹ต


 

โ€ป ์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค.
๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
ยซ   2025/04   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
๊ธ€ ๋ณด๊ด€ํ•จ
๋ฐ˜์‘ํ˜•