Middle ware
node express는 라우팅 및 미들웨어로 이루어진 서버 개발 프레임워크이다. 서버는 기본적으로 사용자의 요청을 받으면 이에 대한 응답을 주는 구조로 되어있다. express 에서 클라이언트의 요청은 미들웨어들을 거쳐 서버의 처리 로직으로 전달된다. 즉, 미들웨어는 클라이언트의 요청과 서버의 처리 로직 사이의 경유지라 말할 수 있다.
1. 미들웨어의 형태
const middle1 = (req, res, next) => {
next();
};
미들웨어 함수는 요청 객체(req), 응답 객체(res), 다음 미들웨어에 대한 호출을 인자로 갖는 함수이다. 미들웨어 함수는 req를 통해 요청 데이터에 접근 가능하고, 응답 객체를 이용하여 클라이언트에게 응답을 줄 수 있다. next를 호출하여 다음 미들웨어를 호출할 수 있다.
const middle1 = (req, res, next) => {
console.log("middle1");
next();
};
const middle2 = (req, res, next) => {
console.log("middle2");
next();
};
app.get("/", middle1, middle2, (req, res) => {
console.log("end!");
res.json("response!");
});
위 코드의 출력 결과는 middle1 > middle2 > end! 이다. / 엔드포인트에 대한 요청을 middle1과 middle2를 거쳐왔기 때문이다. 위와 같이 미들웨어 함수를 작성하고 적용할 수 있다.
2. 라우팅 건너뛰기
const router = express.Router();
app.use("/", router);
const middle1 = (req, res, next) => {
console.log("middle1");
next("route");
};
const middle2 = (req, res, next) => {
console.log("middle2");
next();
};
router.get("/", middle1, middle2, (req, res) => {
console.log("end!");
res.json("hello");
});
router.get("/", (req, res) => {
console.log("end2!!");
});
미들웨어 함수의 next 인자는 "route" 혹은 에러 객체를 인자로 가질 수 있다. 이 경우 다음 미들웨어로 이동하는 것이 아니라 특정한 곳으로 이동한다. 예를 들어 "route" 는 중간 미들웨어, 라우터를 뛰어 넘고, 주소와 일치하는 다음 라우터로 이동한다.
위 코드의 출력 결과는 middle1 > end2!! 가 된다. middle1 에서 next("route") 를 호출하면 중간 미들웨어, 처리 함수를 거치지 않고, 경로('/)가 같은 다음 라우터로 넘어간다. 따라서 middle1 후에 end2!! 가 출력되는 것이다.
3. 에러 처리
const middle1 = (req, res, next) => {
console.log("middle1");
next(new Error("middle error"));
}
const middle2 = (req, res, next) => {
console.log("middle2");
next();
}
const handleError = (err, req, res, next) => {
console.log("error", err);
next();
}
app.get("/", middle1, middle2, handleError, (req, res) => {
console.log("end");
});
next의 인자로 에러 객체를 넣으면 오류 처리 미들웨어로 이동한다. 오류처리 미들 웨어 함수는 에러 객체를 의미하는 err이라는 에러 객체를 추가로 인자로 갖는다. 오류 처리 미들웨어에서 개발자는 다음 처리로 넘기거나 사용자에게 응답할 수 있다.
위 코드의 결과는 middle1 > error > end 이다. middle1에서 에러가 발생하여 handleError 함수로 이동되었고, handleError 에서 next() 를 호출하여 처리 함수가 호출되었기 때문이다.
const uploader = multer({
storage: multer.diskStorage({
destination(req, file, cb) {
cb(null, 'uploads/');
},
filename(req, file, cb) {
const ext = path.extname(file.originalname);
cb(null, path.basename(file.originalname, ext) + Date.now() + ext);
},
}),
limits: { fileSize: 5 * 1024 * 1024 },
})
router.post('/upload', uploader.single('file'), (req, res) => {
console.log(req.file);
res.json({ result : `${req.file.filename}`});
})
파일 업로드 요청을 처리하기 위한 미들웨어인 multer는 위와 같이 사용한다. 위 코드에서 multer 에러 처리를 어떻게 추가할 수 있을까?
const upload = uploader.single('file');
router.post(
'/upload',
(req, res, next) => {
uploade(req, res, (error) => {
return error? res.send("fail") : next();
}
}),
(req, res) => {
console.log(req.file);
res.json({ result : `${req.file.filename}`}
)
multer 객체를 감싸고 있는 또 다른 미들웨어를 만들어 에러를 직접 처리할 수 있다.