[Express 미들웨어] 미들웨어란? 미들웨어 작성법

1. Middleware란?
-
HTPP 요청에서 시작해, 최종 응답으로 라우팅하기 전의 중간 단계를 말한다
-
HTTP 요청이 들어온 순간 시작된다.
3) HTTP 요청과 응답 사이에 단계별 동작을 수행해주는 함수다.
-
HTTP 요청 객체를 처리하거나, 응답 객체를 처리, 다음 미들웨어를 실행할 수 있다.
-
HTTP 응답이 최종적으로 마무리될 때까지, 미들웨어 동작 사이클이 실행된다.
-
최종 응답으로 가지 못하게 연결을 끊을 수도 있다.
미들웨어 선언하기
const middleware = (req, res, next) => {
next();
}
req, res, next를 가진 함수를 작성하면 해당 함수는 미들웨어로 동작할 수 있다.- req: HTTP 요청을 처리하는 객체, HTTP 요청 정보가 들었음**- res:** HTTP 응답을 처리하는 객체, 요청에 대한 응답을 반환하는 객체**- next():** 다음 미들웨어를 실행하는 함수
2. 미들웨어 작성법
1. 미들웨어가 없을 경우
response가 즉각 반응한다.
app.get("/", (req, res) => res.send("HomePage Accessed"));
2. 미들웨어를 설정할 경우
3개의 인자(req, res, next)를 사용해야 한다.
const middlewareHome = (req, res, next) => {
console.log("미들웨어 작동 완료");
next();
// next()메소드가 없다면 미들웨어 사이클이 멈춰, 화면은 계속 loading 상태가 된다.
}
app.get("/", middlewareHome,
(req, res) => res.send("HomePage Accessed"));
// 실행 순서
// 1. 미들웨어 작동 완료
// 2. HomePage Accessed
3. 모든 페이지가 사용하는 미들웨어를 생성할 경우
미들웨어는 라우트 이전에 생성해야 작동한다.
미들웨어를 사용하는 코드인 **app.use()**가 app.get()보다 선행되어야 한다.
const globalMiddleware = (req, res, next) => {
if (!isAdmin(req)) {
next(new Error('Not Authorized'));
return;
}
next();
}
app.use(auth);
app.get('/', responseHome);
app.get('/profile', responseProfile);
// 루트 페이지, profile 페이지에 각각 라우트 할 때 globalMiddleware가 작동한다.
4. 미들웨어 서브 스택
use 나 http method 함수에 여러 개의 미들웨어를 동시에 적용할 수 있다. 주로 한 개의 경로에 특정해서 미들웨어를 적용하기 위해 사용한다. 전달된 인자의 순서 순으로 동작한다.
app.use(middleware1, middlware2, ...);
app.use('/admin', auth, adminRouter);
app.get('/', logger, (req, res, next) => {
res.send('Hello Express');
})
3. 미들웨어 사용하기
middleware 는 적용되는 위치에 따라서 어플리케이션 미들웨어, 라우터 미들웨어, 오류처리 미들웨어로 분류할 수 있다. 필요한 동작 방식에 따라 미들웨어를 적용할 위치를 결정하자.
1) application middleware
use 나 http method 함수를 사용하여 미들웨어를 연결할 수 있다. 미들웨어를 모든 요청에 공통적으로 적용하기 위한 방법으로, HTTP 요청이 들어온 순간부터 적용된 순서대로 동작한다.
app.use((req, res, next) => {
console.log(`Request ${req.path}`);
next();
});
app.use(auth);
app.get('/', (req, res, next) => {
res.send('Hello Express');
});
2) router middleware
router 객체에 미들웨어가 적용되는 것 이외에는 어플리케이션 미들웨어와 사용 방법은 동일하다. 특정 경로의 라우팅에만 미들웨어를 적용하기 위한 방법이다. app 객체에 라우터가 적용된 이후로 순서대로 동작한다.
router.use(auth); // 3
router.get('/', (req, res, next) => { // 4
res.send('Hello Router');
});
app.use((req, res, next) => { // 1
console.log(`Request ${req.path}`);
next();
});
app.use('/admin', router); // 2
3) error handleing middleware
오류처리 미들웨어는 일반적으로 가장 마지막에 위치한다. 다른 미들웨어들과는 달리 err, req, res, next 네 가지 인자를 가지며, 앞선 미들웨어에서 next 함수에 인자가 전달되면, 중간 미들웨어들은 뛰어넘고 오류처리 미들웨어가 바로 실행된다.
app.use((req, res, next) => { // 1
if (!isAdmin(req)) {
next(new Error('Not Authorized'));
return;
}
next();
});
app.get('/', (req, res, next) => { // 건너띔
res.send('Hello Express');
});
app.use((err, req, res, next) => { // 2
res.send('Error Occurred');
});
가장 마지막 미들웨어로 오류 처리 미들웨어를 적용하면, 모든 라우팅에 공통적인 오류처리 로직을 적용할 수 있다.
app.use((err, req, res, next) => {
res.status(500);
res.json({
result: 'fail',
error: err.message,
});
});
정의되지 않은 라우팅에 404 오류 처리하기
모든 라우팅이 적용된 이후에 사용되는 미들웨어는 설정된 경로가 없는 요청을 처리하는 Route Handler로 동작한다. Express.js 는 기본적인 404 페이지를 가지고 있지만, 직접 처리가 필요 한 경우 이와 같은 Route Handler를 추가해야한다.
app.use((req, res, next) => {
res.status(404);
res.send({
result: 'fail',
error: `Page not found ${req.path}`
});
});
4) 함수형 미들웨어
하나의 미들웨어를 작성하고, 작동 모드를 선택하면서 사용하고 싶을 경우, API별로 사용자의 권한을 다르게 제한하고 싶은 경우 사용할 수 있다. 함수 실행 시 미들웨어의 동작이 결정되는 방식으로, 동일한 로직에 설정값만 다르게 미들웨어를 사용하고 싶을 경우에 활용된다.
const auth = (memberType) => {
return (req, res, next) => {
if (!checkMember(req, memberType)) {
next(new Error(`member not ${memberType}`));
return;
}
next();
}
}
app.use('/admin', auth('admin'), adminRouter);
app.use('/users', auth('member'), userRouter);