middleware는 이름에서 알 수 있듯이 중간에서 양쪽을 매개하는 소프트웨어다.
즉, A와 B 사이의 미들웨어를 두면 A에서 B로 요청을 보내면 미들웨어가 그 요청을 먼저 받아서 사전에 어떠한 기능을 수행하고 B로 요청을 넘겨주도록 할 수 있다.
프록시가 네트워크 요청을 중개한다면 미들웨어는 어플리케이션, 소프트웨어 간의 중개를 한다.
Express에서는 미들웨어 함수를 선언해서 데이터의 유효성 검증, 사전처리 등을 담당하게 할 수 있다.
다른 라우터 함수가 파라미터로 req
, res
두 가지를 받는 반면, 미들웨어 함수는 next
인자를 받는다. 말 그대로 다음 함수이다.
function func1(req, res, next){
console.log("verify data");
next(); // 다음 (미들웨어)함수 호출
}
app.post('/', func1, (req, res) => {
console.log("process data");
res.status(200).send("success");
})
이렇게 하면 이제 루트로 POST요청이 들어올 경우, 미들웨어가 먼저 실행된 다음 라우터 함수가 작동할 것이다.
> verify data
> process data
물론 필요에 의해 여러개의 미들웨어가 순차적으로 실행되야 할 수도 있다.
이럴 때는 함수 배열을 전달해주면 된다.
예를 들어 아래와 같은 코드가 있다면,
app.post('/', [func1, func2, func3], postSomething)
func1 -> func2 -> func3 -> postSomething 순으로 함수가 호출될 것이다.
이 방식의 장점은 클라이언트에서 들어오는 요청에 대한 대응을 비교적 쉽게 할 수 있다는 것이다.
function func1(req, res, next){
if (not authorized){
res.status(401).send("Unauthorized");
return;
} else {
next();
}
}
만약 첫번째 함수가 유저의 권한을 검사하는 함수라면, 함수2에 넘어오는 요청은 권한 검사를 통과하는 요청 뿐이다. 따라서 미들웨어를 잘 사용하면 중복 코드를 많이 줄이고 편하게 오류 처리를 할 수 있다.
func1에서 가공한 값을 func2, func3에서 써야 한다면?
이럴 때는 res.locals를 활용한다.
function func1(req, res, next){
res.locals.var1 = data;
}
function func2(req, res, next){
if (res.locals.var1 == ~~){
...
}
}
이런식으로 뒷 단의 미들웨어에 값을 넘겨줄 수 있고, 이 변수는 request의 라이프타임 동안에만 유효하기 때문에 클라이언트로 값이 넘어가지는 않는다.
using middleware
passing variables to the next middleware using next in expree.js