http 서버를 이용할 경우, 라우터
를 만들기 위해서 요청 메서드와 주소별로 분기 처리를 해야하기때문에 코드가 매우 복잡해진다.
하지만 express 사용할 경우 라우팅
을 깔끔하게 할 수 있다는 장점이 있다.
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
...
app.use('/', indexRouter);
app.use('/users', usersRouter);
익스프레스 앱과는
app.use('/', indexRouter);
app.use('/users', usersRouter);
로 연결되어있다. app.use
를 사용하기때문에 라우터
도 일종의 미들웨어
라고 볼 수 있다.
또한, 다른 미들웨어
와 다르게 앞에 주소가 붙어있는데, 이와 같이 라우팅 미들웨어
는 첫 번째 인자로 주소를 받아서 특정 주소에 해당하는 요청이 들어왔을때만 미들웨어
가 동작하게 제어할 수 있다.
주소가 /
로 시작하면 routes/index.js
를, /users
로 시작하면, routes/users.js
로 호출하라는 의미이다.
또한 use 대신 get, post, put, patch, delete 같은 HTTP 매서드
를 사용할 수도 있다.
다만, use 매서드는 모든 HTTP 매서드에 대해 요청 주소
만 일치하면 실행되지만 get, post,... 는 요청 주소
뿐만 아니라, HTTP 메서드
까지 일치하는 요청일 때만 실행된다.
이제 라우터
객체에 대해 알아보면, 라우터 파일들은 routers 폴더에 들어있다.
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;
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;
router 객체
는 express.router()
로 만든다.
또, 마지막에는 module.exports = router
로 라우터를 모듈로 만들어준다.
router
도 app처럼 use, get, post, put, patch, delete와 같은 메서드를 붙일 수 있지만, use를 제외하고는 각각 HTTP 요청 메서드와 상응한다.
또, app.use 처럼 router
하나에 여러개의 미들웨어
를 장착할 수도 있다! 실제 라우터 로직이 실행되는 미들웨어 전에 로그인 여부 또는 관리자 여부를 체크하는 미들웨어
를 중간에 넣는다고 한다.
router.get('/', middleware1, middleware2...);
router.get('/')
이면 / 주소로 GET 요청을 하는 것과 같다. 또, res.render
메서드로 클라이언트에 응답을 보낸다. 익스프레스가 응답 객체에 새로 추가한 메서드로, 이 메서드는 템플릿 엔진
을 사용하는 부분이다.
users.js
파일의 경우 /users/로 GET 요청을 했을 때 이 라우터의 콜백 함수가 실행된다.
라우터
에서는 반드시 요청에 대한 응답을 보내거나, 에러 핸들러로 요청을 넘겨야한다! 이때 res 객체
에 들어 있는 메서드들로 응답을 보낸다.
또, next 함수
에서는 라우터에서만 동작하는 특수 기능이 있다.
next('route')
를 이용하면 라우터에 연결된 나머지 미들웨어를 건너뛰고 실행한다.
또, 라우터 주소
에는 특수한 패턴을 사용할 수 있는데,
router.get('/users/:id', function(req,res){
console.log(req.params, res.query);
});
이 코드에서 주소에 :id
란 문자가 있는 것을 확인할 수 있다.
문자 그대로 :id
를 의미하는 것이 아니라, req.params
객체 안에 들어있는 id 값
을 가져오는것을 의미한다.
id가 아니라 type
이 들어갔을 경우 req.params.type
값을 가져온다.
주소에 쿼리 스트링을 쓸때도 있는데, 쿼리스트링의 키-값 정보는 req.query
객체 안에 들어있다.
예를 들어, /users/123?limit=5&skip=10
이라는 주소의 요청이 들어왔을때, req.params
와 req.query
의 객체는 다음과 같다.
{ id : '123' } { limit : '5', skip : '10' }
단, 이 패턴을 사용할때 주의해야하는 점은 일반 라우터
보다 뒤애 위치해야 한다는 점이다. 일반 라우터
뒤에 위치하지 않을 경우, 다른 라우터
를 방해할 수 있다.
에러가 발생하지 않았다면, 라우터
는 요청을 보낸 클라이언트에게 응답을 보내줘야한다.
응답 메서드
의 종류는 send, sendFile, json, redirect, render 등이 있다.
res.redirect(메인 화면 주소)
를 입력)응답 메서드
사용법은 다음과 같다.
redirect(302)를 제외하고 기본적으로 200 HTTP 상태 코드를 응답하지만, status 메서드
를 이용해 직접 바꿀 수도 있다.
res.status(404).send('Not Found')
render 메서드
는 템플릿 엔진
을 렌더링
할 때 사용한다. views 폴더 안 pug 확장자를 가지고 있는 파일들이 템플릿 엔진이다.
마지막으로, 라우터
가 요청을 처리하지 못할 때는 다음 미들웨어로 넘어가는데, 404 HTTP 상태 코드
를 보내줘야하기 때문에 다음 미들웨어에서 새로운 에러를 만들고 에러의 상태코드를 404로 설정한 뒤, 에러 처리를 미들웨어로 넘겨버린다.
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
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');
});
응답을 여러번 보내는 경우
하나의 요청은 한번의 응답만 보낼 수 있다.
응답을 여러번 보낼 경우Can't set headers after they are sent
에러가 발생한다.