프론트엔드에서 무한 스크롤 개발 도중 한 번에 많은 양의 요청을 던졌고 서버에서는 DB 커넥션 수 제한이라는 에러가 발생했다.
한 명의 사용자로부터 너무 반복적인 요청이 오는 것을 어떻게 예외처리 해줘야하는지 알아보자.
npm i express-rate-limit
express-rate-limit 라이브러리를 다운로드 받아준다.
const rateLimit = require('express-rate-limit');
module.exports = rateLimit({
windowMs: 60 * 1000,
max: 3,
handler(req, res) {
res.status(423).send({
message : 'too many request'
});
},
})
우선 테스트를 위해 분당 3번의 요청만 할 수 있도록 설정한다.
postman에서 빠르게 세 번의 요청을 넣어주면
잘 나온다.
이제 10초에 10개의 api를 요청할 수 있도록 셋팅하고 마무리!
같은 유저가 같은 제목의 게시글을 1분 내로 연속적으로 올릴 수 없도록 하는 코드를 만들어 보려고 한다.
postCoolDown.js
const redis = require('redis').createClient();
module.exports = (req, res, next) => {
(async () => {
const title = req.body.title || '';
const loginUserEmail = req.email || '';
try{
await redis.connect();
const existState = await redis.exists(`post_upload_${loginUserEmail}_${title}`);
if(existState){
await redis.disconnect();
res.status(423).send({
message : 'too many request'
});
}else{
await redis.set(`post_upload_${loginUserEmail}_${title}`, 1);
await redis.expire(`post_upload_${loginUserEmail}_${title}`, 60); // 1 minutes
await redis.disconnect();
next();
}
}catch(err){
console.log(err);
if(redis.isOpen){
await redis.disconnect();
}
res.status(409).send({
message : 'unexpected error occured'
});
}
})();
}
redis에 업로드 유저 이름과 게시글 제목을 올리고 만료시간을 1분으로 설정한다. 미들웨어로 등록해준 다음에 바로 테스트 해보자.
1분 안에 같은 제목의 게시글을 넣으려고 하면 잘 막힌다. 역시 재밌다...
추가 고려 사항 : redis에 key값으로 넣을 수 있는 string길이는 제한되어 있다. 그래서 key로 넣을 문자열의 최대 길이를 먼저 파악해야한다.
사용법이 하나도 안 어려웠다. 특히 express-rate-limit
는 적극적으로 사용하도록 하자.