Back Ground

Node - Express [Router 객체로 라우팅 분리] 본문

Javascript/Node.js

Node - Express [Router 객체로 라우팅 분리]

Back 2019. 2. 27. 05:51



Router 객체로 라우팅 분리하기


이전 라우터를 만들 때 요청 메서드와 주소별로 분기 처리를 하느라 코드가 매우 복잡했다.


if문으로 분기하여 코딩하여 보기에도 좋지 않고 확장하기도 어렵다.

익스프레스를 사용하는 이유 중 하나가 바로 라우팅을 깔끔하게 관리할 수 있다는 점 때문이다.




app.js

1
2
3
4
5
6
7
...
var indexRouter = require('./routes/index');
var userRouter = require('./routes/users');
...
app.use('/',indexRouter);
app.use('/users',usersRouter);
...
cs


익스프레스 앱과는 app.use('/',indexRouter)와 app.use('/users', usersRouter)로 연결되어 있다.

다른 미들웨어와는 다르게 앞에 주소가 붙어 있다.

이와 같이 라우팅 미들웨어는 

첫 번째 인자로 주소를 받아서 특정 주소에 해당하는 요청이 왔을 때만 미들웨어가 동작하게 할 수도 있다.


주소가 /로 시작하면 routes/index.js를, 

         /users로 시작하면 routes/users.js를 호출하라는 의미이다.



use 대신 

  • get
  • post
  • patch
  • delete

같은 HTTP 메서드를 사용할 수도 있다.



1
2
3
4
5
6
7
8
9
10
11
12
app.use('/',function(req,res,next){
    console.log('/ 주소의 요청일 때 실행된다.');
    next();
});
app.get('/',function(req,res,next){
    console.log('GET 메서드 / 주소의 요청일 때만 실행 된다.');
    next();
});
aap.post('/data',function(req,res,next){
    console.log('POST 메서드 / data 주소의 요청일 때만 실행된다.');
    next();
});
cs




use메서드는 모든 HTTP 메서드에 대해 요청 주소만 일치하면 실행되지만 

get, post, put, patch, delete 같은 메서드는 주소뿐만 아니라 HTTP 메서드까지 일치 하는 요청일 때만 실행된다. 




이제 라우터를 살펴보겠다.

라우터 파일들은 routes폴더에 들어 있다.

index와 users라우터는 다음과 같다.


routes/index.js

1
2
3
4
5
6
7
8
9
var express = require('express');
var router = express.Router();
 
/* GET home page. */
router.get('/'function(req, res, next) {
  res.render('index', { title: 'Express' });
});
 
module.exports = router;
cs




routes/users.js

1
2
3
4
5
6
7
8
9
10
var express = require('express');
var router = express.Router();
 
/* GET users listing. */
router.get('/'function(req, res, next) {
  res.send('respond with a resource');
});
 
module.exports = router;
 
cs


router 객체는 express.Router()로 만들었다.

마지막에는 module.exprots = router;로 라우터를 모둘로 만든다.


router에도 app처럼 use, get, post, put, patch, delete 같은 메서드를 붙일 수 있다.

use를 제외하고는 각각 HTTP 요청 메서드와 상응한다.


또한, app.use처럼 router 하나에 미들웨어를 여러 개 장착할 수도 있다. 

실제 라우터 로직이 실행되는 미들웨어전에 

로그인 여부 또는 관리자 여부를 체크하는 미들웨어를 중간에 넣어 두곤한다.

다음과 같은 것이 가능하다는 뜻이다.


1
router.get('/', middleware1, middleware2, middleware3);
cs


다시 코드 설명으로 돌아가겠다.

router.get('/')이면 / 주소로 [ GET요청 ]을 하는 것과 같다.

res.render 메서드로 클라이언트에 응답을 보낸다.

익스프레스가 응답 객체에 새로 추가한 메서드이다.

이 메서드는 템플릿 엔진을 사용하는 부분이다.



user.js에서도 router.get('/')부분이 있다.

app.js에서 app.use('/users', usersRouter)로 연결했기 때문에

 /users와 /이 합쳐져 /users로 GET 요청을 했을 때 이 라우터의 콜백 함수가 실행된다.



사실 라우터(express.Router())를 사용할 필요 없이 

app.js에서 app.get('/', 미들웨어), app, get( '/users', 미들웨어 )를 해도 기능은 동일한다.

하지만 코드 관리를 위해 라우터를 별도로 분리하는 것이다.



라우터에서는 반드시 요청에 대한 응답을 보내거나 에러 핸들러로 요청을 넘겨야 한다.

응답을 보내지 않으면 브라우저는 계속 응답을 기다린다.

응답에 제한 시간이 있으므로 영원히 기다리지는 않지만,

기다리는 동안 다른 동작을 수행할 수 없는 수도 있다.

res객체에 들어 있는 메서드들로 응답을 보낸다.




next함수에는 라우터에서만 동작하는 특수 기능이 있다.

next('route')이다.

라우터에 연결된 나머지 미들웨어들을 건너뛰고 싶을 때 사용한다.



1
2
3
4
5
6
7
8
9
10
11
12
router.get('/'function(req,res,next){
    next('route');
},function(req,res,next){
    console.log('설치 되지 않았습니다.');
},function(req,res,next){
    next();
});
 
router.get('/',function(req,res){
    console.log('실행됩니다');
    res.render('index',{title:'Express'});
})
cs



같은 주소의 라우터를 두 개 만들었다.

첫 번째 라우터의 첫 번째 미들웨어에서 next('router')를 호출하자 

두 번째, 세 번째 미들웨어는 실행되지 않는다.

대신 주소와 일치하는 다음 라우터로 넘어간다.



 




[유용한 팁]

라우터 주소에는 특수한 패턴을 사용할 수 있다.

여러 가지 패턴이 있지만, 자주 쓰이는 패턴 하나만 알아본다.


1
2
3
router.get('/users/:id'function(req,res){
    console.log(req.params, req.query)
});
cs


주소에 :id가 있는데.. 

문자 그대로 :id를 의미하는 것이 아니다.

이 부분에는 다른 값을 넣을 수 있다. 


/users/1이나 /users/123 등의 요청도 이 라우터에 걸린다.

이 방식의 장점은 :id에 해당하는 1이나 123을 조회할 수 있다는 점이다.

req.params 객체안에 들어 있다.


ex)

:idreq.params.id로, 

:type이면 req.params.type으로 조회할 수 있다.



주소에 쿼리스트링을 쓸 때도 있다.

쿼리스트링의 키-값 정보는 req.query객체 안에 들어 있다.


예를 들어 /users/123?limit=5&skip=10이라는 주소의 요청이 들어왔을 때

req.paramsreq.query객체는 다음같다.

1
{id : '123'} , {limut:'5', skip: '10'}
cs

(:id 라는 키를 지정해서 파라메터의 123 데이터를 가져올 수 있다.)



[패턴 사용 시 주의]

일반 라우터 보다 뒤에 위치해야 한다는것!

다양한 라우터를 아루는 와일드카드 역할을 하므로 일반 라우터보다는 뒤에 위치해야 다른 라우터를 방해하지 않는다.








라우터는 요청을 보낸 클라이언트에게 응답을 보내주어야 한다.


[ 응답 메서드 ]

  • send
  • sendFile
  • json
  • redirect
  • render

.. 등등 있다. [ 자주 쓰이는 응답 메서드]





■ send만능 메서드


- 버퍼 데이터나 문자열을 전송하거나,

- HTML 코드를 전송하기도 하고,

- JSON데이터도 전송할 수 있다.




■ sendFile파일을 응답으로 보내주는 메서드




■ jsonJSON데이터를 보내준다.




■ redirect는 응답을 다른 라우터로 보내 버린다.

예를 들어 로그인 완료 후 다시 메인화면으로 돌아갈 때 res.redirect(메인 화면 주소)를 하면 된다.



1
2
3
4
5
res.send(버퍼 또는 문자열 또는 HTML 또는 JSON);
res.sendFile(파일 경로);
res.json(JSON 데이터);
res.redirect(주소);
res.render('템플릿 파일 경로',{ 변수 });
cs


기본적으로는 200 HTTP 상태 코드를 응답하지만(res.redirect는 302),

직접 바꿔줄 수도 있다.

다음과 같이 status 메서드를 먼저 사용하면 된다.



1
res.status(404).send('Not Found')
cs


render메서드는 템플릿 엔진을 렌더링할 때 사용한다.

views폴더 안 pug 확장자를 가지고 있는 파일들이 템플릿 엔진이다.





응답을 여러 번 보내는 경우


하나의 요청에 대한 응답은 한 번만 보내야 한다 .

두 번 이상 보내면 다음과 같은 에러가 발생한다.


[ 콘솔 ]

Error: Can't set headers after they are sent.

    at validateHeader (_http_outgoing.js:489:11)

    at ServerResponse.setHeader(_http_outgoing.js:496:3)

...


이와 같은 에러를 보았다면 라우터에서 res 객체의 응답 메서드가 두번 이상 사용되지 않았는지 점검해보아야 한다.

 








마지막으로 라우터가 요청을 처리하지 못할 때 어떤 일이 발생하는지 알아본다.


요청을 처리할 수 있는 라우터가 없다면 다음 미들웨어로 넘어간다.

404HTTP 상태코드를 보내주어야 하므로 다음 미들웨어에서

새로운 에러를 만들고 에러의 상태코드를 404로 설정한 뒤 에러 처리 미들웨어 넘겨 버린다.


app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
 
// 404 처리 미들웨어
app.use(function(req, res, next) {
  next(createError(404));
});
 
// 에러 핸들러
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env'=== 'development' ? err : {};
 
  // render the error page
  res.status(err.status || 500);
  res.render('error');
});
 
...
cs




'Javascript > Node.js' 카테고리의 다른 글

WebPack의 기본 개념  (0) 2019.03.01
Node - Event Loop  (0) 2019.03.01
Node - Express 미들웨어 connect-flash  (0) 2019.02.27
Node - Express 미들웨어 express-session  (0) 2019.02.27
Node - Express 미들웨어 static  (0) 2019.02.27
Comments