Express
Express는 Node.js의 핵심 모듈로 http와 connect 컴포넌트를 기반으로 하는 웹 프레임워크 입니다.
서버의 페이지 개수가 늘어나고 사이트가 커지면 코드가 복잡해지는데 Express 프레임워크를 사용하게 되면 코드의 양도 줄고 추후 유지보수가 쉽도록 만들어줍니다.
http를 통해서 Node.js 만을 사용하여 클라이언트와 통신할 때와 Express를 사용하여 클라이언트와 통신할 때를 비교하면 다음과 같습니다.
클라이언트의 요청을 받아서 처리한 후, 다시 클라이언트에게 응답한다는 점은 같지만 중간에 미들웨어들을 거친다는 점이 다릅니다.
Node.js만 사용하여 http서버를 통신하게 되면 Node.js 에 등록된 콜백들을 사용하여 처리하고, Express를 사용하면 Express 내부에 개발자가 사용하고자 하는 미들웨어를 설치하여 해당 미들웨어들을 거쳐 통신하는 것입니다.
미들웨어란
미들웨어는 Express의 핵심이라고 할 수 있습니다. 요청과 응답 중간에 위치한다고 하여 미들웨어라고 부릅니다.
라우터와 에러 핸들러 또한 미들웨어의 일종이므로 미들웨어가 Express의 전부라고도 할 수 있습니다.
미들웨어는 요청과 응답을 조작하여 기능을 추가하기도 하고, 나쁜 요청들을 걸러내기도 합니다.
미들웨어는 주로 app.use와 함께 사용되는데 위의 그림을 코드로 옮겨보면 아래와 같이 사용할 수 있습니다.
const express = require('express');
const session = require('session');
const cors = require('cors');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const app = express();
app.use(
cors({
origin: ['http://localhost:3000'],
methods: ['GET', 'POST'],
credentials: true,
})
);
app.use(bodyParser.json());
app.use(cookieParser());
app.use(
session({
secret: 'hyojin', // 세션 발급에 필요한 비공개 키
resave: false, // 세션을 저장하고 불러올 때 세션을 다시 저장 할 지 여부
saveUninitialized: true, // 세션에 저장 할 때 초기화 여부
})
);
express를 호출하여 app 이라는 변수 객체를 만들었고 이제 이 app 변수에 app.use와 같이 각종 기능들을 연결할 수 있습니다.
미들웨어는 주로 app.use 와 같이 사용되는데 app.use 메서드의 인자로 들어 있는 함수가 미들웨어입니다.
미들웨어는 use메서드로 인해서 app에 장착되는 것이고 가장 상단의 코드부터 순차적으로 미들웨어들을 거친 후 라우터에서 클라이언트로 응답을 보냅니다.
body-parser
body-parser는 요청의 본문을 해석해주는 미들웨어입니다. 주로 form 데이터나 AJAX 요청의 데이터를 처리합니다.
Express 4.16.0 버전 이후 부터는 body-parser의 일부 기능이 Express에 내장되어서 경우에 따라 body-parser를 따로 설치하지 않고도 사용할 수 있습니다.
app.use(express.json());
app.use(express.urlencoded({extended: false}))
body-parser는 JSON과 URL-encoded 형식의 본문 외에도 Raw, Text 형식의 본문을 추가로 해석할 수 있습니다.
Raw는 본문이 버퍼 데이터일 때, Text는 본문이 텍스트 데이터일 때 해석하는 미들웨어입니다.
JSON은 JSON 형식의 데이터 전달 방식이고, URL-encoded는 주소 형식으로 데이터를 보내는 방식입니다.
위에서 설명한 것처럼 보통 form 전송이 URL-encoded 방식을 사용하고 urlencoded 메서드를 보면 {extended: false} 라는 옵션이 있는데 이 옵션이 false이면 노드의 querystring 모듈을 사용하여 쿼리스트링을 해석하고, true이면 qs 모듈을 사용하여 쿼리스트링을 해석합니다. qs 모듈은 내장 모듈이 아닌 npm 패키지이며, querystring 모듈의 기능을 좀 더 확장한 모듈입니다.
cors에 관한 설명은 web security 에서 더 자세히 설명하고 있으니 생략하겠습니다.
req객체 정리
- req.body : POST 정보를 가지고 있습니다. 파싱을 위해서 body-parser와 같은 미들웨어를 필요로 하는데 ,그 이유는 요청 정보가 url에 들어있는 것이 아니라 Request의 본문에 들어있기 때문입니다.
- req.query : GET 정보를 가지고 있습니다. 즉, url로 전송 된 쿼리 스트링 파라미터를 담고 있습니다.
- req.headers : HTTP의 Header 정보를 가지고 있습니다.
res 객체 정리
- res.send : 다양한 유형의 응답을 전송합니다.
- res.redirect : 브라우저를 리다이렉트 합니다.
- res.json : JSON 응답을 전송합니다.
- res.end : 응답 프로세스를 종료합니다.
res.send / res.json / res.end 의 차이점
res.send
res.send()의 인자에는 Buffer, String, Object, Array 가 올 수 있습니다. 그리고 response Header에는 Body의 Content-Type이 "자동으로" 정의됩니다.
res.send({ name: 'hyojin' })
key는 name, value는 'hyojin'이라는 object를 인자에 넣어서 response 응답을 전달하면, response Header 내 Content-Type은 자동으로 json 으로 정의됩니다.
res.json
res.json은 JSON으로 응답을 보내는 것입니다. res.send 도 Object를 응답으로 보내기 때문에 res.json을 왜 만든것인지 의문이 들 수 있는데, res.json은 JSON 정보를 전달하는데 좀 더 특화된 기능을 가지고 있습니다.
JSON과 Object는 서로 다른 차이점을 가지고 있습니다.
JSON은 String, Number, Object, Array, Boolean, Null을 지원하지만, Function, Date, Undefined 와 같은 타입은 지원하지 않습니다.
따라서 JSON에서 지원하지 않는 타입들을 파라미터로 입력하게 되면 JSON이 지원하지 않는 타입이기 때문에 JSON이 지원하는 타입으로 변환하는 작업을 JSON.stringify()를 통해 거쳐주어야만 합니다.
즉, res.json을 사용하면 JSON.stringify() 를 통해 파라미터를 JSON string 형태로 먼저 변환 한 후, res.send()를 호출하여 응답을 내보내야합니다.
res.end
res.end는 응답 프로세스를 종료할 때 사용됩니다.
res.end 를 항상 써줘야하는 것은 아니고 데이터를 제공하지 않고 응답을 끝내려면 res.end()를 사용할 수 있습니다.
예를들어 다음 코드와 같이 상태코드만 전달한 후 응답을 종료하기 위해서 써줄 수 있습니다.
res.status(200).end();
응답 데이터를 res.json이나 res.send와 같은 형태로 전송하는 경우에는 이 메서드들이 일부 데이터를 보낸 뒤에 자동으로 응답 종료처리를 하기 때문에 res.end() 를 호출할 필요가 없습니다.