6장 익스프레스 웹 서버 만들기
6-1. 익스프레스 프로젝트 시작하기
익스프레스: 서버를 제작하는 과정에서 겪게 되는 불편을 해소하고 편의 기능을 추가한 웹 서버 프레임워크. http 모듈의 요청과 응답 객체에 추가 기능들을 부여함. 기존 메서드 외에도 편리한 메서드들을 추가해 기능을 보완함.
express 외에도 koa나 hapi 등의 웹 서버 프레임워크가 있지만 express 사용량이 압도적이다.
본격적으로 들어가기 앞서 프로젝트를 생성한다.
- 4번: express 모듈을 실행해 app 변수에 할당한다.
- 5번: app.set('port', port)로 서버의 포트를 설정한다. env에 PORT가 있다면 해당 값을, 없다면 3000을 이용한다.
- 7번: app.get('path', router), 주소에 get 요청이 들어왔을 때 어떤 동작을 할 지 작성한다. express에서는 res.write나 res.end 대신 res.send를 사용하면 된다.
- 10번: /html에 get 요청이 들어오면 index.html을 반환한다. 이때 res.send가 아닌 res.sendFile을 사용한다.
- 14번: http 모듈과 동일하게 listen을 한다. app.set()으로 지정한 port를 app.get('port')
localhost:3000 | localhost:3000/html |
6-2. 자주 사용하는 미들웨어
미들웨어: 요청과 응답의 중간(middle)에서 작동함. 요청과 응답을 조작해 기능을 추가하기도 하고, 나쁜 요청을 걸러내기도 함.
많은 기능이 미들웨어기 때문에 익스프레스는 미들웨어라고 해도 과언이 아닐 정도라고 한다.
미들웨어는 app.use(미들웨어) 형식으로 사용한다. 서버에 미들웨어를 연결해보자,
app.use()에 있는 미들웨어의 세 번째 매개변수에 next가 있는데 이는 다음 미들웨어로 넘어가는 함수이다. next를 실행하지 않으면 다음 미들웨어가 실행되지 않는다.
미들웨어는 다음 표와 같이 실행된다
app.use(미들웨어) | 모든 요청에서 미들웨어 실행 |
app.use('/abc', 미들웨어) | abc로 시작하는 요청에서 미들웨어 실행 |
app.post('/abc'), 미들웨어) | abc로 시작하는 POST 요청에서 미들웨어 실행 |
app.get()에서 볼 수 있듯이 같은 라우터에 미들웨어를 여러개 장착할 수도 있다. 다만 이때도 next()가 있어야 다음 함수가 실행된다.
미들웨어 종류
- morgan: 요청과 응답에 대한 정보를 콘솔에 출력. 인수에 따라 로그가 바뀐다.
- static: 정적인 파일들을 제공하는 라우터 역할. 따로 설치하지 않고 express객체 안에서 꺼내면 된다. 요청 주소와 실제 주소가 다르기 때문에 유용하다. 또한 정적인 파일들을 알아서 제공해주므로 FS 모듈을 사용할 필요가 없다.
- body-parser: 요청의 본문에 있는 데이터를 해석해서 req.body 객체로 만들어주는 미들웨어. 보통 폼 데이터나 AJAX 요청의 데이터를 처리한다. 단, 멀티파트(이미지, 동영상, 파일)데이터는 처리하지 못한다.
- cookie-parser: 요청에 동봉된 쿠키를 해석해 req.cookies 객체로 만든다. 쿠키를 생성하거나 제거하는 기능은 없다.
- express-session: 세션 관리용 미들웨어. 인수로 세션에 대한 설정을 받는다.
- resave: 요청이 올 때 세션에 수정 사항이 생기지 않더라도 세션을 다시 저장할지 설정
- saveUninitialized: 세션에 저장할 내역이 없더라도 처음부터 세션을 생성할지 설정
- secret: 쿠키를 서명할 때 필요함. cookie-parser와 동일하게 설정하는 것이 좋다.
- name: 세션 쿠키의 이름을 설정.
- cookie: 세션 쿠키에 대한 설정. maxAge, domain, path, expires 등 일반적인 쿠키 옵션이 모두 제공됨.
saveUninitialized를 true로 설정하면 쿠키가 발행된 걸 확인할 수 있다. 여기서 쿠키의 앞부분이 s: 실제로는 s%3A인 것을 볼 수 있는데 이는 express-session으로 만든 쿠키의 특징이라고 한다.
- multer: 이미지, 동영상 등을 비롯한 여러 가지 파일을 멀티파트 형식으로 업로드할 때 사용하는 미들웨어.
- 미들웨어의 특성 사용하기
- next()함수에 route라는 문자열을 넣으면 바로 다음 라우터의 미들웨어로 이동한다. 그 외의 인수를 넣으면 에러 처리 미들웨어로 이동한다.
- res.locals 객체에 데이터를 넣어 미들웨어 간에 데이터를 전달할 수 있다. res.locals.data = "데이터 넣기"
- 미들웨어 안에 미들웨어를 넣는 것도 가능하다. 조건문을 이용하여 분기 처리를 할 수도 있다.
6-3. Router 객체로 라우팅 분리하기
http 모듈로 서버를 만들 때는 요청 메서드와 주소별로 분기를 나누느라 보기에도 좋지 않고 확장하기도 어려웠다. 익스프레스를 사용하면 라우팅을 깔끔하게 관리할 수 있다.
app.get 같은 메서드가 라우터 부분인데 라우터를 많이 연결해 코드가 길어지게 하는 것보단 라우터를 분리하는 게 좋다.
routes폴더를 만들고 그 안에 GET / 라우터인 index.js와 GET /user 라우터인 user.js를 작성한다.
이후 app.js에서 작성한 파일들을 연결하고 404상태코드를 응답하는 미들웨어를 하나 추가한다.
여기서 require('./routes')는 require('./routes/index.js')와 같다. index.js는 생략이 가능하기 때문이다.
또한 이 글에 작성하진 않았지만 index와 user에 app.get('/', ~)가 있는데 여기에 작성된 /와 app.js에서 연결할 때 작성된 /와 /user가 GET / 와 GET /user 라우터가 된다.
localhost:3000/ | localhost:3000/user |
라우터 주소에는 정규표현식을 비롯한 특수한 패턴을 사용할 수 있다. 그 중 하나가 매개변수라고 하는 패턴인데 :param 형식으로 주소의 해당 부분에 있는 값을 req.params.param에서 접근할 수 있다. 아래의 경우 req.params.id이다.
여기서 주의할 점은 매개변수 패턴은 일반 라우터보다 뒤에 위치해야 한다는 점이다. :id 부분이 와일드 카드 역할을 하므로 9~11번째 줄의 코드는 절대 실행되지 않는다.
주소에 쿼리스트링을 쓸 수도 있다. 쿼리스트링의 키-값 정보는 req.query 객체 안에 들어있다.
이때 일치하는 값이 없으면 아까 추가해둔 404 상태코드를 응답하는 미들웨어가 동작한다.
6-4. req, res 객체 살펴보기
익스프레스의 req, res 객체는 http 모듈의 req, res 객체를 확장한 것이다다. 기존 http 모듈의 메서드도 사용할 수 있고, 익스프레스가 추가한 메서드나 속성을 사용할 수도 있다.
익스프레스가 많은 속성과 메서드를 추가했지만 그 중에서도 자주 쓰이는 것들은 다음과 같다.
- req
- req.app: req 객체를 통해 app 객체에 접근할 수 있습니다. req.app.get('port')와 같은 식으로 사용할 수 있다.
- req.body: body-parser 미들웨어가 만드는 요청의 본문을 해석한 객체.
- req.cookies: cookie-parser 미들웨어가 만드는 요청의 쿠키를 해석한 객체.
- req.ip: 요청의 ip 주소가 담겨 있다.
- req.params: 라우트 매개변수에 대한 정보가 담긴 객체.
- req.query: 쿼리스트링에 대한 정보가 담긴 객체.
- req.signedCookies: 서명된 쿠키들은 req.cookies 대신 여기에 담겨 있다.
- req.get(헤더 이름): 헤더의 값을 가져오고 싶을 때 사용하는 메서드.
- res
- res.app: req.app처럼 res 객체를 통해 app 객체에 접근할 수 있다.
- res.cookie(키, 값, 옵션): 쿠키를 설정하는 메서드.
- res.clearCookie(키, 값, 옵션): 쿠키를 제거하는 메서드.
- res.end(): 데이터 없이 응답을 보낸다.
- res.json(JSON): JSON 형식의 응답을 보낸다.
- res.locals: 하나의 요청 안에서 미들웨어 간에 데이터를 전달하고 싶을 때 사용하는 객체.
- res.redirect(주소): 리다이렉트할 주소와 함께 응답을 보낸다.
- res.render(뷰, 데이터): 다음 절에서 다룰 템플릿 엔진을 렌더링해서 응답할 때 사용하는 메서드.
- res.send(데이터): 데이터와 함께 응답을 보낸다. 데이터는 문자열일 수도, HTML일 수도, 버퍼일 수도, 객체나 배열일 수도 있다.
- res.sendFile(경로): 경로에 위치한 파일을 응답한다.
- res.set(헤더, 값): 응답의 헤더를 설정한다.
- res.status(코드): 응답 시의 HTTP 상태 코드를 지정한다.
6-5. 템플릿 엔진 사용하기
템플릿 엔진은 자바스크립트를 사용해서 HTML을 렌더링할 수 있게 한다.
이 설명을 봤을 때 리액트가 바로 떠올랐지만 HTML생성을 서버에서 하는지 클라이언트에서 하는지 등이 다르다. 요즘에는 템플릿 엔진 대신 리액트나 뷰를 많이 사용한다고 한다.
템플릿 엔진은 기존 HTML과는 문법이 다를 수도 있고, 자바스크립트 문법이 들어가있기도 하다. 또한 각 엔진마다 문법이 다르기도 하기 때문에 여기서 각 엔진의 문법을 모두 정리하기 보다는 엔진의 특징만 정리하기로 하였다.
- 퍼그(제이드)
- 루비와 비슷한 문법으로, 문법이 간단해 코드양이 줄어들기 때문에 선호하는 사람이 많다.
- HTML과 너무 다른 문법 때문에 호불호가 갈린다.
- <>가 없고, 닫는 태그가 존재하지 않는다. 탭과 스페이스로만 부모 자식 관계를 규명한다.
- 넌적스
- HTML 문법을 그대로 사용하되 추가로 자바스크립트 문법을 사용할 수 있다.
- 공통점
- 자바스크립트 변수를 HTML에 렌더링할 수 있다.
- 반복문이나 조건문이 사용 가능하다.
- 다른 HTML 파일을 넣을 수 있다. 또한 레이아웃을 정할 수 있다.
6-5-3. 에러 처리 미들웨어
res.locals 속성에 값을 대입해 템플릿 엔진에 변수를 주입할 수 있다.
error 객체의 스택 트레이스는 시스템 환경이 production(배포 환경)이 아닌 경우에만 표시된다.
404 아래의 Error 부분이 스택 트레이스인데 스택 트레이스를 통해 서버 폴더 구조를 유추할 수 있으므로 배포 환경에서는 숨기는 것이다.
6-6. 함께 보면 좋은 자료
- Express 공식 홈페이지: http://expressjs.com
- 퍼그 공식 홈페이지: https://pugjs.org
- 넌적스 공식 홈페이지: https://mozilla.github.io/nunjucks
- morgan: https://github.com/expressjs/morgan
- body-parser: https://github.com/expressjs/body-parser
- cookie-parser: https://github.com/expressjs/cookie-parser
- static: https://github.com/expressjs/serve-static
- express-session: https://github.com/expressjs/session
- multer: https://github.com/expressjs/multer
- dotenv: https://github.com/motdotla/dotenv
'WINK-(Web & App) > Express.js (Node.js) 스터디' 카테고리의 다른 글
[2024-2 Node.js 스터디] 김민재 #3주차 - 익스프레스 웹 서버 만들기 (1) | 2024.11.04 |
---|---|
[2024-2 Node.js 스터디] 류상우 #2주차 (2) | 2024.10.14 |
[2024-2 Node.js 스터디] 김민재 #2주차 - HTTP 모듈로 서버 만들기 (4) | 2024.10.12 |
[2024-2 Node.js 스터디] 류상우 #1주차 (0) | 2024.10.07 |
[2024-2 Node.js 스터디] 김민재 #1주차 (0) | 2024.10.06 |