이번 포스팅에서는 라우터와 미들웨어에 대해 살펴보고자 한다.
< 목차 >
- 라우터와 미들웨어
- 미들웨어의 매개변수
- 미들웨어를 변수로 만들어 사용하기
- 라우트 매개변수
< 라우터와 미들웨어 >
Node.js의 express 모듈을 이용해 아래와 같이 간단한 서버를 만들어 보자.
const express = require('express');
const app = express();
app.get('/express', (req, res)=>{
res.send('<h1>Hello server!!</h1>')
})
app.listen(3000, ()=>{
console.log('server onload')
})
라우터와 미들웨어가 무엇인지에 대해 알아보기 위해 최소한의 기능만 구현되어 있는 서버를 만들었다.
"http://localhost:3000/express" 로 접속했을 때 위와 같은 페이지가 보이게 될 것이다. 웹브라우저에서 '/express' 경로로 get 방식의 요청을 보낸 것을 app.get( '/', (req, res) => { res.send('<h1>Hello server!!</h1>') } ) 을 이용해 처리해준 것이다. 해당 코드를 조금 자세히 들여다 보자.
app.get('/express', (req, res)=>{ res.send('<h1>Hello server!!</h1>') })
// app.get <- 라우터
// (req, res) => { } <- 미들웨어
app.get에 해당하는 부분을 우리는 라우터(router)라고 한다. 그리고 (req, res) => { }에 해당하는 부분이 바로 미들웨어(middleware)이다. 라우터는 웹브라우저의 요청을 처리해주는 역할을 담당하고 있고 웹브라우저에서 요청이 왔을 때 미들웨어를 실행시켜주게 된다. 즉, 라우터는 요청 URL에 따라 미들웨어를 실행시켜주는 장치라고 생각할 수 있다. '/express' 경로로 요청이 들어왔을 때 미들웨어인 (req, res) => { }가 실행되게끔 app.get이 처리를 해주고 있는 것이다.
그렇다면 (req, res) => { } 부분을 일컫는 미들웨어란 도대체 무엇일까?? 미들웨어는 쉽게 말해 라우터의 함수라고 생각하면 된다. request 객체와 response 객체에 접근하여 그 사이에서 특정 작업을 처리해주는 역할을 하고 있는 것이 바로 미들웨어이다.
< 미들웨어의 매개변수 >
미들웨어에는 4개의 매개변수가 존재한다. 위에서 사용된 미들웨어는 req, res 두개의 매개변수를 갖고 있는 형태이고 여기에 세번째 매개변수로 next라는 매개변수를 추가할 수 있다. 네번째 매개변수는 에러처리에 사용되는 매개변수인데 에러처리는 나중에 따로 다루도록 하고 next 매개변수에 대해 좀 더 알아보자.
next 매개변수의 기능에 대해 알아보기 전에 app.use에 대해 잠깐 살펴보고 넘어가자. app.use 역시 app.get과 같은 라우터의 일종이다. app.get이 get 방식의 요청을 처리하는 라우터라면 app.use는 웹브라우저로부터 오는 모든 요청을 처리하는 라우터이다. request method가 어떤 것이든지에 상관없이 app.use 라우터는 첫번째 인자값에 해당하는 경로로 요청이 들어왔을 때 해당 요청을 처리해준다. 맨 위에 있는 코드에 app.use 라우터를 추가해보도록 하자.
const express = require('express');
const app = express();
app.use('/express', (req, res)=>{
console.log("next")
})
app.get('/express', (req, res)=>{
res.send('<h1>Hello server!!</h1>')
})
app.listen(3000, ()=>{
console.log('server onload')
})
javascript 파일이 실행될 때 파일 안에 작성된 코드들이 위에서부터 아래로 순서대로 실행되는 것처럼 라우터 역시 기본적으로 앞에 있는 라우터가 먼저 실행된다. 다시말해, 라우터에도 실행순서가 존재한다는 것이다. 위에 있는 코드를 살펴보면 app.use 라우터가 app.get 라우터 보다 먼저 작성된 것을 볼 수 있다. app.use와 app.get 둘 다 '/express' 경로로 들어온 요청을 처리하게 되는데 이처럼 같은 경로의 요청을 처리하는 라우터가 두 개 이상 작성되어 있을 경우 먼저 작성된 라우터만 실행되게 된다. 라우터는 기본적으로 1개의 요청에 대해 1개의 라우터만 실행되기 때문이다.
위에 보이는 것과 같이 "http://localhost:3000/express"로 접속했을 때 app.use 라우터의 미들웨어에 있는 console.log('next')에 의해 next는 출력되지만 app.get 라우터는 실행되지 않고 있는 것을 확인할 수 있다. 그리고 app.use 라우터에서 응답 처리를 해주고 있지 않기 때문에 브라우저는 계속해서 응답 대기 상태로 있는 것이다.
이러한 상황에서 사용하는 것이 바로 미들웨어의 세번째 매개변수인 next이다. app.use 라우터의 미들웨어에 매개변수로 next를 추가해주고 next( ) 함수를 실행시켜보자.
const express = require('express');
const app = express();
app.use('/express', (req, res, next)=>{
console.log("next")
next()
})
app.get('/express', (req, res)=>{
res.send('<h1>Hello server!!</h1>')
})
app.listen(3000, ()=>{
console.log('server onload')
})
app.use 라우터에 의해 console.log('next')가 실행되면서 app.get 라우터도 제 기능을 하고 있는 것을 확인할 수 있을 것이다.
'/express' 경로로 들어온 요청을 app.use 라우터가 처리하는 과정에서 미들웨어의 세번째 인자값으로 들어온 next() 함수가 호출되면 아래쪽에서 '/express' 경로로 들어온 요청을 처리해 줄 수 있는 라우터가 있는지 다시한번 찾는 작업을 수행한다. 그리고 조건에 맞는 라우터가 있다면 한번 더 실행하게 되는 것이다. 기본적으로 라우터는 1개의 요청에 대해 1개의 라우터만 실행되지만 동일한 경로의 요청에 대해 그 다음에 작성된 라우터도 실행하고 싶을 때 사용하는 것이 바로 미들웨어의 세번째 인자값으로 오는 next인 것이다.
이번에는 next 매개변수가 하나의 라우터 안에서 미들웨어를 참조하는 경우를 살펴보자.
기본적으로 라우터가 가질 수 있는 인자값의 갯수에는 제한이 없다. 즉, 라우터는 n개의 인자값을 가질 수 있는 것이다. 인자값이 1개일 경우에는 인자값으로 미들웨어만 들어간 형태를 하고 있다. 경로가 생략되어 있는 것인데 1개의 인자값을 갖고 있을 때는 '/' 경로가 생략된 형태라고 생각하면 된다. 2개 이상의 인자값을 가질 때는 첫번째 인자값으로 uri를, 두번째 이후의 모든 인자값들은 전부 미들웨어기 된다.
// 인자값이 1개일 때
app.get((req, res)=>{ })
// app.get('/', (req, res)=>{ }) 와 동일한 의미
// 인자값이 2개일 때
app.get('/express', (req, res)=>{ })
// 인자값이 3개일 때
app.get('/express', (req, res)=>{ }, (req, res)=>{ })
// 인자값이 4개일 때
app.get('/express', (req, res)=>{ }, (req, res)=>{ }, (req, res)=>{ })
// 라우터는 미들웨어를 늘려가는 형식으로 n개의 인자값을 가질 수 있다.
이 때 app.get 라우터에 3개의 인자값을 주고 그 안에서 next 함수를 사용하면 app.use를 사용했을 때와 같은 효과를 얻을 수 있다. 다음과 같이 코드를 작성해주면 된다.
const express = require('express');
const app = express();
app.get('/express', (req, res, next)=>{
console.log("next")
next()
}, (req, res)=>{
res.send('<h1>Hello server!!</h1>')
})
app.listen(3000, ()=>{
console.log('server onload')
})
app.use 라우터에서 next함수를 사용했을 때와 똑같이 작동하는 것을 확인할 수 있을 것이다. 이는 같은 라우터 안에 미들웨어가 2개 이상 존재할 경우 next() 함수에 의해 다음에 위치한 미들웨어를 참조할 수 있게 되기 때문이다.
next() 함수는 기본적으로 같은 라우터 안에서 참조할 미들웨어를 찾는다. 그리고 같은 라우터 안에 참조할 미들웨어가 없을 경우, 다음 라우터에서 참조할 미들웨어를 찾게 된다. 그렇기 때문에 미들웨어를 사용할 때는 코드의 순서가 가장 중요하다. 라우터를 적는 순서에 따라서 같은 코드라 할지라도 다른 결과값을 가져올 수 있기 때문이다. 다시한번 언급하지만 미들웨어를 사용할 때는 반드시 순서에 유념하도록 하자.
< 미들웨어를 변수로 만들어 사용하기 >
위에서 본 것과 같이 하나의 라우터 안에는 무수히 많은 미들웨어가 들어갈 수 있다. 그렇기 때문에 아무런 조작없이 계속해서 미들웨어를 추가하다 보면 코드 자체의 가독성도 떨어지고 내용을 구분하기도 쉽지 않게 된다. 하지만 다행히도 미들웨어는 변수에 담아 사용하는 것이 가능하다. 하나의 라우터 안에서 여러 개의 미들웨어가 사용될 경우, 미들웨어를 변수로 빼서 사용하는 것이 가능하다는 것이다.
const express = require('express');
const app = express();
let middle = (req, res, next) => {
console.log('next')
next()
}
app.get('/express', middle, (req, res)=>{
res.send('<h1>Hello server!!</h1>')
})
app.listen(3000, ()=>{
console.log('server onload')
})
이처럼 미들웨어만을 변수에 집어 넣고 사용하는 것이 가능하기 때문에 우리는 라우터와 미들웨어를 분리해서 코드를 작성할 수 있게 된다. 분리가 가능하다는 것은 결국 다른 파일 안에 존재하는 함수 역시 미들웨어로 사용할 수 있다는 뜻이기도 하다.
< 라우트 매개변수 >
마지막으로 라우트 매개변수에 대해 알아보도록 하자.
라우트 매개변수를 이용하면 아래와 같이 라우터에 변수를 넣어서 사용할 수 있다.
app.get('/:ingoo', (req, res)=>{
let name = req.params.ingoo
res.send(`<h1>hello ${name}</h1>`)
})
라우트 매개변수를 사용하고자 할 경우 "/:ingoo" 처럼 콜론(:)을 넣어주어야 한다. 그리고 콜론 이후에 작성하는 것은 uri가 아닌 변수명이 된다. 즉, 여기서 ingoo는 uri가 아니라 변수명이 되는 것이다. 라우트 매개변수를 사용하게 되면 uri의 내용들을 변수로 가져오는 것이 가능해진다. req.params.ingoo 를 사용해 uri의 내용을 ingoo라는 변수에 담아서 가져올 수 있다. 이해가 잘 안된다면 코드가 실행된 결과물을 살펴보도록 하자.
"http://localhost:3000/express" 로 접속했을 때 기존처럼 잘 작동하는 것을 확인할 수 있다. 하지만 라우터를 설정해주지 않은 uri를 입력하게 되면 어떻게 될까?
"http://localhost:3000/qwerasdf" 와 같이 임의의 uri를 입력해도 라우트 매개변수에 의해 '/' 이후에 작성된 uri를 변수로 받게된다. 여기서는 ingoo라는 변수명을 사용해 그 내용을 받았다. 그리고 변수명의 내용을 받아오는 방법이 바로 req.params.변수명 인 것이다.
하지만 라우트 매개변수를 사욯할 때는 주의해야 할 점이 있다. 바로 작성 순서이다. 아래와 같이 순서를 바꿔놓고 실행하면 의도치 않은 결과값을 얻게 된다.
const express = require('express');
const app = express();
app.get('/:ingoo', (req, res)=>{
let name = req.params.ingoo
res.send(`<h1>hello ${name}</h1>`)
})
app.get('/express', (req, res, next)=>{
console.log("next")
next()
}, (req, res)=>{
res.send('<h1>Hello server!!</h1>')
})
app.listen(3000, ()=>{
console.log('server onload')
})
"http://localhost:3000/express" 로 접속했는데 "Hello server!!"가 아닌 "hello express"가 나오는 것을 확인할 수 있다. 위에서 언급했던 라우터의 실행 순서에 의해 "/express" 경로로 들어온 요청을 라우트 매개변수로 받아버리는 상황이 발생한 것이다. 따라서 라우트 매개변수를 사용할 때는 라우터의 실행 순서를 고려해서 조심히 사용해야만 한다. 다시한번 강조하지만 라우터를 작성할 때는 무엇보다 실행 순서에 주의해서 작성해야 한다.
'Node > Express' 카테고리의 다른 글
Node.js - express (10) express-session 사용하기 (2) | 2022.02.12 |
---|---|
Node.js - express (9) express.Router() 사용하기 (0) | 2022.02.10 |
Node.js - express (7) 세션(session) (2) | 2022.02.09 |
Node.js - express (6) cookieParser 함수 만들기 (1) | 2022.02.07 |
Node.js - express (5) 쿠키(cookie) (0) | 2022.02.07 |