본문 바로가기
JavaScript│Node js

미들웨어 패턴 - 서비스 로직 접근 제한

by 자유코딩 2018. 10. 10.

Rest api에 post , put 접근 할 때는 입력 값을 가지고 접근하게 된다. 


입력 값 들은 서버 코드에서 검증 과정을 거치기도 한다.


그런데 서버 코드의 서비스 로직에서만 입력 값을 검증하지는 않는다.


사용 인증에 관한 부분은 미들웨어에서 처리하기도 한다.


이렇게 하면 인증을 통과하지 못했을 때 , 실제 서비스 로직에 접근하지 못하도록 막을 수 있다.


서비스 로직에 접근하지 못하도록 막는 "미들웨어 패턴"에 대해서 알아본다.




미들웨어는 익스프레스( Express )의 핵심이다. 


미들웨어는 요청과 응답의 중간( middle )에 위치해서 미들웨어라고 부른다.




node js에서 미들웨어는 주로 app.use와 함께 사용된다.


아래 코드는 app.use가 많이 쓰이는 app.js 코드이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
 
app.use(function(req, res, next) {
  const num = parseInt(req.param('num'));
  if (isNaN(num)) {
      res.status(400).send('input is wrong');
      return;
  }
    console.log('저도 미들웨어 입니다.');
    next();
});
app.use('/', indexRouter);
 
// 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');
});
 
module.exports = app;
cs


여기서 app.use 메소드의 인자로 들어 있는 함수가 미들웨어 입니다.


미들웨어는 use 메소드로 app에 장착됩니다.


여기서 핵심은. app.js를 위에서부터 차례대로 거친 후에 라우터에서 클라이언트로 응답을 보낸다.


입력 검사를 하는   app.use는 맨 위에 적으면 된다.


그런데 이렇게 코드를 작성하면 문제가 있다.


조금 규모가 큰 프로그램을 생각해보자.


app.js에 직접 로직을 작성하면 app.js의 코드가 아주 길어진다. 이것은 좋지 않다.


그래서 이 코드를 아래와 같이 변경했다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
 
app.use('/',indexRouter);
 
// 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');
});
 
module.exports = app;
cs


맨 위에는 app.use('/', indexRouter) 만 남겨 두었다.


그리고 indexRouter에 해당하는 index.js 에서 입력 값 검증을 했다.


아래 코드 처럼 작성했다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const express = require('express');
const router = express.Router();
 
/* GET home page. */
router.get('/'function(req, res, next){
    const num = parseInt(req.param('num'),10);
    if (isNaN(num)) {
        res.status(400).send('input is wrong');
        return;
    }
    next();
},(req, res, next) => {
    const num = parseInt(req.param('num'),10);
    let numbers = [...Array(9)];
    let resultString = '';
    let i = 1;
    numbers.forEach((item,index) => {
        numbers[index] = i;
        resultString += `${num}*${numbers[index]}=${num * numbers[index]} `;
        i++;
    });
    res.status(200);
    res.render('index', { title : 'Express', numbers : resultString});
    res.end();
});
module.exports = router;
 
cs


router.get의 매개변수로 함수 2개를 넣었다.


입력 값이 잘못 되었다면 첫번째 함수에서 return 문을 만나서 종료된다.


입력 값이 올바른 경우에는 next를 통해서 뒤의 arrow function 이 호출된다.


그런데 이렇게 작성하면 코드가 직관적이지 못하다.


그래서 이렇게 바꿨다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const express = require('express');
const router = express.Router();
 
/* GET home page. */
router.get('/', checkInput,(req, res) => {
    const num = parseInt(req.param('num'),10);
    let resultString = '';
 
    [...Array(9)].forEach((item,index) => {
        resultString += `${num}*${index + 1}=${num * (index + 1)} `;
    });
 
    res.status(200);
    res.render('index', { title : 'Express', numbers : resultString});
    res.end();
});
 
function checkInput(req,res,next) {
    const num = parseInt(req.param('num'),10);
    if (isNaN(num)) {
        res.status(400).send('input is wrong');
        return;
    }
    next();
}
 
module.exports = router;
cs


함수를 router.get에 매개변수로 전달했다.


댓글