node 미들웨어

bunny.log·2022년 10월 5일
0

Node

목록 보기
9/9

미들웨어

말 그대로 요청(Request)과 응답(Response) 사이 중간(middle)에서 핸들링해주는 익스프레스의 핵심 기능이다.

사용법

use메서드를 사용하고 요청 메서드 내부에서 미들웨어를 정의할 수 있다.

//모든 요청에서 미들웨어 실행
 app.use((req, res, next)=> {
 	console.log('middle ware execute');
 	next();
 }, (req, res) => {
 	// code..
 });;
 
 //특정 요청 또는 경로에서 미들웨어 실행 (next 인자는 생략 가능)
app.get(('/', (req, res, next)=>{
	console.log("request get, '/'");
	next();
}, (req, res)=>{
	throw new Error('error!');
});

연속성

여러 인자로 콜백 함수를 전달하면 연달아 미들웨어를 사용할 수 있다.

app.use(
     (req, res, next) => {
         console.log('first middleware!');
         next();
     },
     (req, res, next) => {
         console.log('second middleware!');
         next();
     },
    (req, res, next) => {
        console.log('thrid middleware!');
        next();
    }
);

app.get('/', (req, res) => {
    console.log('complete!');
});

미들웨어 확장

미들웨어 내부에 미들웨어를 삽입하는 방식으로, 예를 들어 특정 사용자별 다른 리소스를 응답하여야 할 경우에 사용한다.
원리는 미들웨어의 패턴인 (req, res, next) 내부적으로콜백을 전달하는 방식이다. 이러한 패턴을 미들웨어 확장법이라 한다.

app.use('/user', (req, res, next) => {
    if (req.session.id) {
        express.static(__dirname, 'assests')(req, res, next);
    } else {
        next();
    }
});

혹시 여러 미들웨어에서 요청 값을 공유하고 싶다면?

혹시 여러 미들웨어에서 요청 값을 공유하고 싶다면 미들웨어의 request인수에 값을 저장하면 요청이 끝나기 전 까지 서로 다른 미들웨어에서 공유할 수 있다.

절대로 전역변수(app.set)을 통해 클라이언트의 데이터를 공유해서는 안된다.

// custom middleware
app.get('/', (req, res, next) => {
    req.data = 'jiny';
    next();
});

app.get('/', (req, res) => {
    res.send(`${req.data}`); //jiny
});

에러 핸들링

에러 처리도 마찬가지로 미들웨어로 핸들링 할 수 있다.
주의사항으로는 에러 미들웨어는 반드시 인자 4개 (error, req, res, next)를 꼭 받아야한다.
(인자를 굳이 쓰지 않아도 반드시 넘겨주어야한다. 함수 취급 자체가 달라진다.)

app.use((err, req, res, next) => {
    console.err(err);
});

에러 처리 미들웨어로 보내는 방법은 next콜백에 여러 객체를 넣어주는 방법이 있다.

next에 에러 인자가 들어가게 되면 알아서 에러처리 미들웨어로 실행하도록 한다.

에러는 예고 없이 일어나기 때문에 try-catch로 핸들링 해야한다.

app.use(
     (req, res, next) => {
         console.log('middle ware execute!');
         next();
     },
     (req, res, next) => {
         try {
             throw new Error('error!!'); //고의적인 에러 발생
         } catch (error) {
            next(error);
        }
    }
);

//에러 핸들링 미들웨어
app.use((err, req, res, next) => {
    console.error(err);
    // http 규칙 상 500으로 전달되어야하긴 하지만, 보안 위협을 방지하여 200으로 속인다.
    res.status(200).send('undefined error');
});

morgan

morgan에 연결 후 포트에 접속하면 기존 로그 외에 추가적인 로그를 볼 수 있다.
morgan은 요청과 응답에 대한 정보를 콘솔에 기록한다.

const express = require('express');
const path = require('path');
const morgan = require('morgan'); // 미들웨어 연결
 
const app = express();
app.set('port', process.env.PORT || 3000);
 
// 로그 기록
if (process.env.NODE_ENV === 'production') { 
   app.use(morgan('combined')); // 배포환경이면
} else {
   app.use(morgan('dev')); // 개발환경이면
}
 
app.get('/', (req, res) => { 
   res.send('Hello, index');
});
 
app.listen(app.get('port'), () => {
  console.log(app.get('port'), '번 포트에서 대기 중');
});

위 코드에서는 인수로 dev를 넣었는데 이 외에 combined, common, short, tiny 등을 넣을 수 있다. combined를 하면 로그가 더 자세해진다.

개발 환경에서는 dev를, 배포 환경에서는 combined를 이용하면 좋다.

dev 요청 url과 응답 시간을 출력한다.
1GET /test 200 3.063 ms - 4

common 접속 ip와 요청 시각을 출력한다.
1::1 - - [02/Jan/2022:07:34:31 +0000] "GET /test HTTP/1.1" 200 4

combined 상세한 정보를 출력한다. (브라우저, 접속 환경, ip)
1::1 - - [02/Jan/2022:07:36:54 +0000] "GET /test HTTP/1.1" 200 4 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"

cookieparser

쿠키 파싱을 편하게 해주는 라이브러리

const cookieparser = require('cookie-parser');
const app = express();

app.set('port', 3111);

//[private-key] 비밀키 옵션 (암호화)
app.use(cookieparser('jiny'));

쿠키 얻어오기

req 인수를 통해 쿠키 값을 가져올 수 있다. 일반 쿠키이면 req.cookies를 사용하고 서명된 쿠키이면 req.signedCookies를 사용한다. (서명 쿠키일 때 signed옵션을 true로 줘야한다.)

app.get('/', (req, res) => {
    req.signedCookies; //서명이 된 쿠키
});

쿠키 생성하기
res 인수의 cookie메서드를 통해 쿠키를 전송할 수 있다.
사용 방법은 아래와 같다. 인자에 순서대로 쿠키 이름, 값, 쿠키 옵션 객체 등을 넣어주면된다.

app.get('/', (req, res) => {
    res.cookie('cookie-name', 'cookie-value', {
        expires: new Date(Date.now() + 1000000),
        httpOnly: true,
        path: '/',
        signed: true
    });
    res.send('main');
});

쿠키 삭제하기
더 이상 필요가 없는 쿠키는 clearCookie 메서드로 삭제할 수 있다.
쿠키를 삭제할 때는 key-value와 옵션도 정확히 일치해야한다.

app.get('/clear', (req, res) => {
    res.clearCookie('cookie-name', 'cookie-value', {
        expires: new Date(Date.now() + 1000000),
        httpOnly: true,
        path: '/'
    });
    res.send('clear-cookie!');
});

static

express 환경에서 정적인 파일(html, css 등등..)들을 제공하는 일종의 라우터 역할을 하는 미들웨어이다. 요청 경로와 실제 경로를 다르게 설정 할 수 있어 상대적으로 보안에도 조금 도움이 된다.

여러 미들웨어들을 사용할 때 첫 부분에 와야 자원 낭비를 조금이나마(?) 줄일 수 있다. (미들웨어의 순서는 생각하면서 작성)

const express = require('express');
const app = express();

app.use('/', express.static('/public'));
//디렉토리 절대 경로 식을 사용하면 더 안정적이다.
app.use('/', express.static(__dirname + 'public'));

express-session

세션을 효율적으로 관리할 수 있게 하는 라이브러리이다. 요청 클라이언트 마다 별도의 데이터를 set 해 앱 내에서 관리할 수 있다. (로그인 기능, 임시 데이터 등)

1.5 버전 이전이라면 cookie-parser미들웨어 보다 앞에 선언해야한다.

npm i express-session

express-session을 import 후, 인자로 세션에 대한 설정 객체를 넘기면 된다.

const session = require('express-session');
 
 app.use(
     session({
         resave: true, //항상 세션을 덮어씌울지
         saveUninitialized: false, //처음부터 세션을 생성할지
         secret: 'secret-key', //쿠키 서명 값
         cookie: {
             //세션 쿠키 옵션
            httpOnly: true,
            secure: false
        },
        name: 'session-cookie' //세션 쿠키 이름 (defalut : connect.sid)
    })
);

dotenv

시스템 내의 환경 변수를 효율적으로 관리해주는 라이브러리이다. 기존 node에서 존재하는 process.env객체로 관리하는 것과 같은 역할을 한다. (비밀키와 같은 외부에 노출되어야 하지 않는 값들에 사용한다.)

npm install dotenv

프로젝트 메인 파일에서 dotenv모듈을 불러온 뒤 config()함수를 호출만 하면 된다. 주의 할 사항은 먼저 process.env를 읽어버리면 안된다. 그래서 보통 소스 최상위 라인에 dotenv.config 호출을 위치시킨다.

const dotenv = require('dotenv');
dotenv.config();

전역변수 app.set()

참고 https://jinyisland.kr/post/middleware/

profile
나를 위한 경험기록

0개의 댓글