안녕하세요, 코린이의 코딩 학습기 채니 입니다.
[Node.js 교과서]의 책을 참고하여 포스팅한 개인 공부 내용입니다.
API 사용량 제한하기
- 과도한 API 사용으로 인해 서버에 무리가 갈 수 있음
- 무료 사용자는 1시간에 10번 허용, 유료 사용자는 1시간에 100번 허용 등 API 사용량을 제한
패키지 설치
$ yarn add express-rate-limit
express-rate-limit 패키지를 이용하여 API 사용량을 제한할 수 있습니다.
API 별로 혹은 Router 별로 미들웨어를 만들어 사용합니다.
미들웨어 생성
middlewares/index.ts
const limiter = rateLimit({
windowMs: 60 * 10000,
max: (req: Request, res: Response) => {
if (req.user?.type === "premium") {
return 100;
}
return 10;
},
handler(req: Request, res: Response) {
res.status(res.statusCode).json({
code: res.statusCode,
message: "사용 횟수를 초과했습니다.",
});
},
});
// 디도스 공격에는 효과가 없을 수 있음.
// 미들웨어 확장패턴
export const apiLimiter = async (req: Request, res: Response, next: NextFunction) => {
try {
let user: User | null = null;
if (res.locals.decoded?.id) {
user = await User.findOne({ where: { id: res.locals.decoded.id } });
if (user) {
req.user = user;
}
}
limiter(req, res, next);
} catch (err: any) {
next(err);
}
};
User의 type이 premium이라면, 1분에 100번 사용
User의 type이 premium이 아니라면, 1분에 10번 사용할 수 있도록 제한합니다.
미들웨어 확장 패턴을 이용하여 사용자의 type를 구한 후 해당 type에 대해서 제한량이 상이한 미들웨어를 생성했습니다.
⭐️ 사용량이 누적되지 않고 계속 초기화 되어 삽질했던 거 기록..
잘못된 코드
export const apiLimiter = async (req: Request, res: Response, next: NextFunction) => {
try {
let user: User | null = null;
if (res.locals.decoded?.id) {
user = await User.findOne({ where: { id: res.locals.decoded.id } });
}
rateLimit({
windowMs: 60 * 10000, // ms단위
max: 1,
// 요청 횟수 초과 시 실행되는 callback 함수
handler(_req: Request, _res: Response) {
_res.status(_res.statusCode).json({
code: _res.statusCode,
message: "사용 횟수를 초과하였습니다.",
});
},
})(req, res, next);
} catch (err: any) {
next(err);
}
};
rateLimit가 새롭게 호출되어 횟수가 누적되지 않고 초기화되어 설정한 max를 넘어가도 제한이 되지 않았던 것..!
따라서 위처럼 따로 분리하여 초기화 되지 않도록 처리해주었습니다.
(참고한 사이트)
https://www.inflearn.com/questions/919591/10-6-%EC%9E%AC%EC%A7%88%EB%AC%B8
middlewares/index.ts
/**
* 버전이 올라가면서 사용하면 안되는 API에 대해서 deprecated 함수를 구현
* @param req
* @param res
*/
export const deprecated = (req: Request, res: Response) => {
res.status(410).json({ code: 410, message: "새로운 버전이 나왔습니다. 새로운 버전을 이용해주세요." });
};
더이상 사용이 불가한 API에 대한 사용을 막아주는 미들웨어를 생성해주었습니다.
미들웨어 적용
routes/v1.ts (이전 버전 API)
import express from "express";
import { deprecated, verifyToken } from "../middlewares";
import { createToken, getMyPosts, getPostsByHashtag, tokenTest } from "../controllers/v1";
const router = express.Router();
// 미들웨어를 router마다 사용하지 않고, 공통되기 때문에 아래처럼 사용
router.use(deprecated);
router.post("/token", createToken);
router.get("/test", verifyToken, tokenTest);
router.get("/posts/my", verifyToken, getMyPosts);
router.get("/posts/hashtag/:title", verifyToken, getPostsByHashtag);
export default router;
모든 router에 미들웨어를 하나하나 작성해줄 수 있지만, router.use()를 이용하여 해당 router에 대해서 미들웨어를 한 번에 적용해줄 수도 있습니다.
v1 버전 API 요청 시
router/v2.ts (최신 버전 - API 사용량 제한)
import express from "express";
import { verifyToken, apiLimiter } from "../middlewares";
import { createToken, getMyPosts, getPostsByHashtag, tokenTest } from "../controllers/v2";
const router = express.Router();
router.post("/token", apiLimiter, createToken);
router.get("/test", verifyToken, apiLimiter, tokenTest);
router.get("/posts/my", verifyToken, apiLimiter, getMyPosts);
router.get("/posts/hashtag/:title", apiLimiter, getPostsByHashtag);
export default router;
모든 router에 대해서 사용량을 제한해주었습니다.
apiLimiter 미들웨어에서 res.locals.decoded를 사용하기 때문에 verifyToken 미들웨어 뒤에 위치해야 하여 이번에는 API별로 미들웨어를 장착시켜주었습니다.
10번이 초과되니 위처럼 사용 횟수를 초과했다는 오류 메세지를 리턴 받은 것을 확인할 수 있습니다.
'JavaScript > Node.js' 카테고리의 다른 글
Node) 노드버드 SNS 만들기 - 게시글, 이미지 업로드 하기 (0) | 2023.07.31 |
---|---|
Node) Sequelize Migration (0) | 2023.07.28 |
Node) 사용자 인증 정보 확인 후 다음 미들웨어에게 해당 정보 넘겨주기 (0) | 2023.02.03 |
Node) 부모 라우터의 req.params를 자식 라우터에게 넘기기 - 중첩라우터 (0) | 2023.02.02 |
Node) React + Node로 infinity scroll 페이징 처리 (observer) (0) | 2023.01.25 |