Javascript/Next.js

[ Next.js ] - next api에서 express-rate-limit 사용하기

algml0703 2022. 7. 26. 21:10
반응형

기본적으로 express-rate-limit은 무분별한 요청으로 인한 서버 과부하를 막기 위해 사용되는 라이브러리이다.

백엔드 서버를 제대로 구축하여 express-rate-limit을 사용하는 것은 express-rate-limit문서에 나온 그대로 사용하면 문제없이 사용할 수 있지만 next에서 express-rate-limit을  그대로 사용하면 에러가 나고 제대로 작동하지 않기 때문에 해당 라이브러리를 사용하기 위해서는 수정하여 사용하여야 한다.

기본적인 express-rate-limit 사용 ☞ 2022.06.02 - [Javascript/Node.js] - [ Node.js ] - 서버 DDos 공격 막기

사용방법

next 환경 구축

> npx create-next-app --ts
// 위의 명령어 입력 후 enter를 계속 누른다.

tsconfig.json 의 설정은 아래와 같이 맞추어 준다.

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "incremental": true
  },
  "include": [
    "pages/_app.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

최상단 디렉토리에서 utils 폴더 생성, utils폴더안에는 주로 서비스 로직이 들어가게 된다. utils폴더 안에 rateLimit.ts 파일을 생성하여 준다. 폴더 구조는 아래와 같은 모습을 갖게 된다.

rateLimit 파일

import rateLimit from 'express-rate-limit'
import slowDown from 'express-slow-down'

const applyMiddleware = middleware => (request, response) =>
  new Promise((resolve, reject) => {
    middleware(request, response, result =>
      result instanceof Error ? reject(result) : resolve(result)
    )
  })

const getIP = request =>
  request.ip ||
  request.headers['x-forwarded-for'] ||   
  request.headers['x-real-ip'] ||
  request.connection.remoteAddress
// 사용자 ip를 알기 위함이다.


export const getRateLimitMiddlewares = ({
  limit = 1,
  windowMs = 1000, 
  //delayAfter = Math.round(10 / 2),
  //delayMs = 500,
} = {}) => [
  //slowDown({ keyGenerator: getIP, windowMs, delayAfter, delayMs }),
  rateLimit({ keyGenerator: getIP, windowMs, max: limit }),
]

const middlewares = getRateLimitMiddlewares()

async function applyRateLimit(request, response) {
  await Promise.all(
    middlewares
      .map(applyMiddleware)
      .map(middleware => middleware(request, response))
  )
}

export default applyRateLimit

express-slow-down
express-slow-down은 응답 속도를 늦춰주는 라이브러리이다. express-slow-down은 아직 사용법이 아리송해서 주석처리하고 express-rate-limit만 사용하였다.

getRateLimitMiddlewares
getRateLimitMiddlewares를 통해 api 제한 설정을 할 수 있다.

request.headers['x-forwarded-for']
클라이언트와 서버 중간에 트래픽이 프록시나 로드밸런서를 거치면, 서버 접근 로그에는 요청자의 원 ip가 아닌 프록시나 로드밸런서의 ip주소만을 담게 된다. 이때에 실제 요청자의 ip정보를 담고있는 헤더로 XFF 헤더라고도 한다.
마찬가지로 request.iprequest.headers['x-real-ip'], request.connection.remoteAddress 모두 사용자의 ip를 얻기 위한 부분이다.

Promise.all()
Promise.all()은 인자값으로 배열을 주고, 해당 배열의 작업이 모두 완료되면, 순서가 보장된 결과값을 반환하여 준다.

api 파일 

pages/api 폴더안에 hello.ts 파일안에 아래와 같이 작성하여 준다.

import type { NextApiRequest, NextApiResponse } from "next";
import nc from 'next-connect';
import { v4 as uuid } from 'uuid';
import rateLimit from '../../utils/rateLimit'


const handle = nc()
    .get(async(req: NextApiRequest, res:NextApiResponse)=>{
        await rateLimit(req, res)
        const result = uuid()
        return res.status(200).json(result)
    })

export default handle

위의 작업까지 마친 후 > yarn dev로 실행한뒤 localhost:3000/hello 에 접속하면 uuid가 생성된 것이 나오고 계속해서 새로고침하여, 설정한 이상으로 요청하게 되면 Too may requests, please try again later. 이 나온다.

 

출처 

express-rate-limit을 next에서 사용하기 ☞   https://kittygiraudel.com/2022/05/16/rate-limit-nextjs-api-routes/

x-forwarded-forhttps://developer.mozilla.org/ko/docs/Web/HTTP/Headers/X-Forwarded-For

반응형