MiddleWare
미들웨어는 express의 핵심이다. 요청과 응답의 중간에 위치하여 미들웨어라고 하며, 라우터와 에러 핸들로 또한 미들웨어의 일종이므로 미들웨어가 express의 전부라고 봐도 무방하다.
미들웨어 함수는 req(요청) 객체, res(응답) 객체, 그리고 애플리케이션 요청-응답 사이클 도중 그 다음의 미들웨어 함수에 대한 액세스 권한을 갖는 함수이다.
다음 미들웨어 함수에 대한 액세스는 next 함수를 이용해서 다음 미들웨어로 현재 요청을 넘길 수 있다. next라는 말에서 알 수 있듯이 next를 통해 미들웨어는 순차적으로 처리한다.(순서가 중요!)
next 함수는 인자의 종류로 구분이 가능한데, 인자를 아무것도 넣지 않으면 단순하게 다음 미들웨어로 넘어간다. next 함수의 인자로 route를 넣어 next('route')
와 같이 사용하면, 라우터에 연결된 나머지 미들웨어들을 건너뛰고 주소와 일치하는 다음 라우터로 넘어가게 된다. 그 외에 다른 값을 인자로 넣으면 다른 미들웨어나 라우터를 모두 건너 뛰고 바로 에러 핸들러로 이동하며 넣어준 값은 에러에 대한 내용으로 간주된다.
미들웨어는 주로 app.use와 함께 사용되고, 미들웨어는 use 메서드로 app에 장착한다.
1 | const express = require('express'); |
반드시 미들웨어 안에서 next()
를 호출해야 다음 미들웨어로 넘어간다. logger
나 express.json()
, express.urlencode
, cookieParser
, express.static
모두 내부적으로는 next()
를 호출하기 때문에 다음 미들웨어로 넘어갈 수 있는 것이다.
미들웨어 종류
morgan
요청에 대한 정보를 콘솔에 기록해주는 미들웨어 app.use(logger('dev'))
에서 함수의 인자로 dev
short
common
combined
등을 줄 수 있다. 개발 시에는 dev
나 short
를 많이 사용하고, 배포 시에는 common
이나 combined
를 많이 사용한다.
body-parser
요청의 본문을 해석해주는 미들웨어이다. 보통 폼 데이터나 ajax 요청의 데이터를 처리한다.
1 | app.use(express.json()); |
express 4.16.0 버전부터는 body-parser
의 일부 기능이 express에 내장되어 따로 설치하지 않고 위와 같이 사용이 가능하다. body-parser
가 필요한 경우도 있는데, json
, url-encoded
형식의 본문 외에도 raw
, text
형식의 본문을 해석할 수 있기 때문이다.
json
은 json
형식의 데이터 전달 방식이고, URL-encoded
는 주소 형식으로 데이터를 보내는 방식이다.
보통 폼 전송이 URL-encoded
방식을 주로 사용한다. urlencode
메소드를 보면 { extended: false }
라는 옵션이 들어있는데, 이 옵션이 false
면 노드의 querystring
모듈을 사용하여 쿼리스트링을 해석하고, true
인 경우 qs
모듈을 사용하여 쿼리스트링을 해석한다. qs
모듈은 내장 모듈이 아니라 npm 패키지이며, querystring
모듈의 기능을 조금 더 확장한 모듈이다.
cookie-parser
cookie-parser
는 요청에 동봉된 쿠키를 해석해준다. 쿠키는 name=kwon;age=25
와 같은 문자열 형식으로 오는데, 이것을 { name: 'kwon', age: '25' }
와 같은 객체로 파싱해준다.
app.use(cookieParser('secret code'))
와 같이 첫 번째 인자로 문자열을 넣을 수 있는데, 암호화된 쿠키가 있는 경우, 인자로 넣은 문자열을 키로 삼아 복호화할 수 있다.
static
static 미들웨어는 정적인 파일들을 제공해주는 express의 내장 미들웨어이다.
1 | app.use(express.static(path.join(__dirname, 'public'))); |
함수의 인자로 정적 파일들이 담긴 폴더를 지정한다. 위와 같은 경우 실세 서버의 폴더 경로에는 public이 들어있지만, 요청 주소에는 public 이 포함되지 않기 때문에 외부에 실제 경로가 유출되지 않아 보안상의 이점도 있다.
1 | app.use('/files', express.static(path.join(__dirname, 'public'))); |
위와 같이 사용하면 /files
라는 가상 경로를 통해 접근하게 할 수 있다.
static 미들웨어는 요청에 부합하는 정적 파일을 발견한 경우 응답으로 해당 파일을 전송하는데, 이러한 경우 다음에 나오는 라우터가 실행되지 않고, 파일을 찾지 못한 경우 다음 라우터로 요청을 넘긴다. 이렇게 자체적으로 정적 파일 라우터 기능을 수행하기 때문에 최대한 위쪽에 배치하는 것이 서버가 쓸데없는 미들웨어 작업을 하는 것을 막을 수 있다. 따라서, 보통 morgan
다음에 배치하는 것이 좋은데 morgan
보다 위로 올리면 정적 파일 요청이 기록되지 않기 때문이다. json
urlencoded
cookie-parser
는 정적 파일을 제공하는데 영향을 끼치지 않기 때문에 굳이 이런 미들웨어를 거칠 필요가 없다.
path 모듈
위에서 사용된 path
는 경로에 관련된 모듈인데, 파일 경로를 작성할 때 문자열을 직접 자르고 합치는 것보다 path에서 제공하는 join함수를 사용하는 것이 편리하다. __dirname
은 node.js에서 제공하는 node파일의 경로를 담고 있는 글로벌 객체이다. path.join()
은 각 파라미터를 합쳐서 경로 문자열을 반환한다. 즉, 위와 같은 path.join(__dirname, 'public')
와 같은 경우 '현재 app.js 파일의 경로 + /public'
을 리턴한다.
express-session
세션 관리용 미들웨어이며, express-generator
로 설치되지는 않기 때문에 따로 설치해주어야 한다.
npm i express-session
1 | app.use(cookieParser(process.env.COOKIE_SECRET)); |
express-session
은 인자로 세션에 대한 설정을 받는다.
resave
: 요청이 왔을 때 세션에 수정 사항이 생기지 않더라도 세션을 다시 저장할지에 대한 설정saveUninitialized
: 세션에 저장할 내역이 없더라도 세션을 저장할지에 대한 설정(보통 방문자 추적 시 사용)secret
: 필수 항목.cookie-parser
의 비밀키와 같은 역할express-session
은 세션 관리 시 클라이언트에 쿠키를 보낸다. 이를 세션 쿠키라고 하는데, 안전하게 쿠키를 전송하려면 쿠키에 서명(암호화)를 해야하고 쿠키를 서명하는 데secret
의 값이 필요하다.cookie-parser
와 같이 설정해야 한다. (위의 코드에서는dotenv
라이브러리를 사용하여 값을 따로 관리했다.dotenv
는 환경변수를 관리해주는 라이브러리인데,.env
파일에 전역적인 정보를 관리하고.gitignore
에.env
파일을 추가하여 공개되지 않도록 해야한다.)
cookie
: 세션 쿠키에 대한 설정 (일반적인 쿠키 옵션이 모두 제공)httpOnly
: 이 옵션을 사용하면 클라이언트에서 쿠키에 접근하지 못하도록 한다.secure
:false
면https
가 아닌 환경에서도 사용 가능,true
면https
에서만 사용 가능- 배포 시에는
ture
로 바꿔서 배포하는 것이 좋음
- 배포 시에는
connect-flash
일회성 메세지들을 웹 브라우저에 나타낼 때 유용한 미들웨어다.
npm i connect-flash
connect-flash
는 cookie-parser
와 express-session
을 사용하기 때문에 이 두 미들웨어보다 아래에 위치시켜야 한다. connect-flash
를 사용하면 req
객체에 req.flash()
메소드를 추가한다. req.flash(key, value)
의 형태로 해당하는 키에 값을 저장하고, req.flash(key)
로 해당 key
의 value
를 불러올 수 있다.
일회성 메세지이기 때문에 로그인이나 회원가입 에러 같은 일회성 경고 메세지 등에 유용할 것이다.
참조
https://psyhm.tistory.com/8
https://psyhm.tistory.com/6
https://nodejs.org/dist/latest-v8.x/docs/api/modules.html#modules_dirname
https://victorydntmd.tistory.com/23
Node.js 교과서