본문 바로가기

NestJS

Throttler를 사용한 Rate Limiting

 해커톤 동안 프로젝트를 하면서 요청을 제한해야 할 일이 생겼다. chatGPT를 사용한다는 것이 그 이유인데, 처음엔 chatGPT billing 문제로 인해 요청을 제한하고 싶었는데, 다른 곳(사용자 인증과 연관된 곳)에서도 써야 될 것이라 생각해 전역으로 적용하기로 했다. 사용 방법은 다음과 같다.

 

 

우선, NestJS에서 제공하는 throttler 패키지를 설치한다. 

yarn add @nestjs/throttler

 

 

설치가 잘 되었다면, rate limiting의 구체적인 내용을 정하면 된다.

AppModule에서 ThrottlerModule을 import 할 때 정하면 된다.

@Module({
  imports: [
    ThrottlerModule.forRoot({
      ttl: 60,
      limit: 10,
    }),
  ],
})
export class AppModule {}

위 코드는 60초 동안 10번으로 요청을 제한한다는 코드이다.

 

 

AppModule의 provider로 등록하면 프로그램 전역에서 사용할 수 있다. APP_GUARD이므로 전역에서 실행된다.

// AppModule
providers: [
  {
    provide: APP_GUARD,
    useClass: ThrottlerGuard,
  },
]

 

 

만약, Throttler를 특정 Controller 에서는 사용하고 싶지 않다면

// UsersController
@SkipThrottle()
@Controller('users')
export class UsersController {
....

@SkipThrottle() 데코레이터를 controller에 붙이면 된다. 

 

 

혹은, 특정 API에서만 사용하고 싶지 않다면

// UsersController
@SkipThrottle()
@Get()
profile(@AuthUser() user: User): ProfileRes {
....

@SkipThrottle() 데코레이터를 API 함수에 붙이면 된다. 

 

 

혹은, 특정 Controller에서만 사용하고 싶다면 해당 Controller의 module에서만 Throttler를 import 하면 된다.

 

 

 

 

 

NestJS는 Throttler를 ip 를 기반으로 적용하기 때문에 proxy처럼 접속을 우회해서 요청하는 경우 제대로 작동하지 않는다. 따라서 proxy 설정을 해 주어야 한다. 우선 proxy 서버 뒤에서 우리 애플리케이션이 실행될 수 있도록 trust proxy 설정을 해 주자. 

 

 

 

 NestJS 는 express 혹은 fastify 둘 중 하나를 기반으로 돌아간다. 

필자는 express 사용하기로 했다.

 main.ts에 해당 내용(trust proxy)을 추가해준다.

// main.ts
async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.set('trust proxy', true);
  await app.listen(3000);
}
bootstrap();

 

 

 이제 기존의 ThrottlerGuard를 상속받아 헤더에서 원본 ip 주소를 가져오는 ThrottlerBehindProxyGuard를 만들면 된다. 공식 문서에 나와있는 코드는 다음과 같다.

// throttler-behind-proxy.guard.ts
import { ThrottlerGuard } from '@nestjs/throttler';
import { Injectable } from '@nestjs/common';

@Injectable()
export class ThrottlerBehindProxyGuard extends ThrottlerGuard {
  protected getTracker(req: Record<string, any>): string {
    return req.ips.length ? req.ips[0] : req.ip; // individualize IP extraction to meet your own needs
  }
}

 

 

 이 파일을 추가했다면, 사용하고 있던 ThrottlerGuard를 ThrottlerBehindProxyGuard로 바꾸면 된다.

'NestJS' 카테고리의 다른 글

CORS, credentials  (0) 2023.08.30
NestJS에서 openAI API 연동으로 ChatGPT 활용하기  (0) 2023.08.30
Provider  (0) 2023.07.24
Controller  (0) 2023.07.20
NestJS의 프로젝트 구조  (0) 2023.07.18