- http 모듈로 웹 서버를 생성하면 굉장히 많은 일을 직접 처리해야 한다.
- express 모듈은 http 모듈에 여러 기능을 추가해 쉽게 사용할 수 있게 마든 모듈이다.
[ express 설치 ]
$ npm install express
1. 기본 서버
[ 코드 - 모듈 추출 ]
//모듈을 추출한다.
var http = require('http');
var express = require('express');
- express 모듈로 서버를 실행하려면 http 모듈이 필요하다.
[ 실행 - express 모듈을 사용한 서버 ]
2. 기본 응답 메서드
app.use(function (request, response) {
- request 이벤트 리스너의 매개변수에는 request 객체와 response 객체가 들어간다.
- express 모듈로 서버를 생성하면 request 객체와 response 객체에 다양한 기능이 추가된다.
- response.send() : 매개변수의 자료형에 따라 적절한 형태로 응답한다.
- response.json() : JSON 형태로 응답한다.
- response.jsonp() : JSONP 형태로 응답한다.
- response.redirect() : 웹 페이지 경로를 강제로 이동한다.
[ send() 메서드의 매개변수 ]
- 문자열 : HTML
- 배열 : JSON
- 객체 : JSON
- 매개변수의 자료형에 따라 적절한 형태로 응답한다.
[ 코드 - send() 메서드 ]
//모듈을 추출한다.
var http = require('http');
var express = require('express');
//서버를 생성한다.
var app = express();
//request 이벤트 리스너를 설정한다.
app.use(function (request, response) {
//데이터를 생성한다.
var output = [];
for (var i = 0; i < 3; i++) {
output.push({
count: i,
name: 'name - ' + i
})
}
//응답한다.
response.send(output);
});
//서버를 실행한다.
http.createServer(app).listen(52273, function () {
console.log('Server running at http://127.0.0.1:52273');
});
[ 실행 - send() 메서드를 사용한 JSON 전달 ]
- send() 메서드에 자바스크립트 객체를 입력했으므로 JSON 형식으로 출력된다.
[ 실행 - send() 메서드를 사용한 오류 전달 ]
[ 실행 - 개발자 도구를 통해 확인 ]
- 사파리 브라우저에서 제공하는 [ 개발자용 > 웹 속성 보기 ]를 통하여 상태가 404 임을 확인할 수 있다.
- IE나 크롬에서도 개발자 도구를 통해 네트워크 상태를 확인할 수 있다.
- header() : 요청 헤더의 속성을 지정 또는 추출한다.
- accepts() : 요청 헤더의 Accept 속성을 확인한다.
- param() : 요청 매개변수를 추출한다.
- is() : 요청 헤더의 Content-Type 속성을 확인한다.
- header() 메서드를 사용하면 쉽게 요청 헤더의 속성을 지정하거나 추출할 수 있다.
- 웹 브라우저에 http://127.0.0.1:52273 에 들어가면 터미널에서 웹 브라우저의 헤더 정보를 볼 수 있다.
- 헤더의 속성을 추출하여 브라우저가 크롬인지 확인할 수 있다.
[ 실행 - 사파리로 접속 ]
[ 실행 - param() 메서드를 사용한 요청 매개변수 추출 ]
- http://127.0.0.1:52273/?name=rint®ion=seoul 로 접속한 화면이다. name과 region 매개변수 값을 출력한다.
- http 모듈과 express 모듈의 가장 큰 차이점은 바로 request 이벤트 리스너를 연결하는데 use() 메서드를 사용한다는 점이다.
- use() 메서드는 여러 번 사용할 수 있다.
- use() 메서드의 매개변수에는 function (request, response, next) { } 형태의 함수를 입력한다.
- 매개변수 next는 다음에 위치하는 함수를 의미한다.
[ 실행 - 콘솔 화면 ]
- use() 메서드의 매개변수로 입력한 함수가 차례대로 실행된다.
- 요청의 응답을 완료하기 전까지 요청 중간중간에서 여러 가지 일을 처리할 수 있다.
- 그래서 use() 메서드의 매개변수에 입력하는 함수를 '미들웨어'라고 부른다.
- 미들웨어에서 request 객체와 response 객체에 속성 또는 메서드를 추가하면 다음 미들웨어에서 추가한 속성과 메서드를 사용할 수 있다.
- 미들웨어를 사용하면 특정한 일을 수행하는 모듈을 분리해서 만들 수 있다.
- logger : 로그 정보를 출력한다.
- csrf : CSEF 보안을 수행한다.
- basicAuth : 기본적인 인증을 수행한다.
- bodyParser : POST 요청 매개변수를 추출한다.
- cookieParser : 쿠키를 분석한다.
- session : 세션 처리를 수행한다.
- methodOverride : 다양한 요청 방식을 수행할 수 있게 한다.
- responseTime : 응답 시간을 계산한다.
- router : 페이지 라우트를 수행한다.
- staticCache : static 미들웨어를 위한 메모리 캐시 층을 생성한다.
- static : 특정 폴더를 서버의 루트 폴더에 올린다.
- directory : 서버의 디렉토리 구조를 보여준다.
- vhost : 가상 호스트를 설정한다.
- favicon : 파비콘을 생성한다.
- limit : POST 요청의 데이터를 제한한다.
- errorHandler : 예외 처리를 수행한다.
- 미들웨어를 사용하면 다른 사람이 만든 기능을 추가할 수도 있고 자신이 과거에 만든 코드도 재사용하기 편리하다.
- morgan 미들웨어는 웹 요청이 들어왔을 때 로그를 출력하는 미들웨어이다.
- express 3.x 버전에서는 express.logger()를 사용했으나 express 4.x 버전부터는 지원하지 않는다. 따라서 morgan 모듈을 설치하여 사용하고자 한다.
[ morgan 미들웨어의 토큰 ]
- :req[header] 요청 헤더를 나타낸다.
- :res[header] 응답 헤더를 나타낸다.
- :http-version HTTP 버전을 나타낸다.
- :response-time 응답 시간을 나타낸다.
- :remote-addr 원격 주소를 나타낸다.
- :date[format] 요청 시간을 나타낸다.
- :method 요청 방식을 나타낸다.
- :url 요청 URL을 나타낸다.
- :referrer 이전 URL을 나타낸다.
- :User-Agent 사용자 에이전트를 나타낸다.
- :status 상태 코드를 나타낸다.
- 웹 브라우저로 http://127.0.0.1:52273 을 호출할 때마다 콘솔에 :method와 :date 에 대한 메시지가 출력된다.
[ 실행 - morgan 미들웨어 토큰 ]
- 웹 브라우저로 http://127.0.0.1:52273 을 3번 호출했다.
- :method 로 GET 요청인지 POST 요청인지 출력한다.
- :date 로 웹 브라우저로 요청한 시간을 출력한다.
[ morgan 미들웨어의 기본 형식 ]
- default :default-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":User-Agent"
- short :remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
- tiny :method :url :status :res[content-length] - :response-time ms
[ 코드 - morgan 미들웨어 기본 형식 ]
//모듈을 추출한다.
var http = require('http');
var express = require('express');
var morgan = require('morgan');
//서버를 생성한다.
var app = express();
//미들웨어를 설정한다.
app.use(morgan('short'));
app.use(function (request, response) {
response.send('<h1>express Basic</h1>');
});
//서버를 실행한다.
http.createServer(app).listen(52273, function () {
console.log('Server running at http://127.0.0.1:52273');
});
[ 실행 - morgan 미들웨어 기본 형식 ]
- short의 형식인 :remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms 로 출력된다.
- static 미들웨어는 웹 서버에서 손쉽게 파일을 제공하는 방법을 제공한다.
- public 폴더를 생성하여 그림 파일, 자바스크립트 파일, CSS 파일 등을 넣는다. 여기에서는 그림 파일을 넣었다.
- 전역변수 __dirname을 사용하여 폴더 위치를 지정하면 나머지는 express 모듈이 전부 알아서 해준다.
- static 미들웨어를 사용하면 지정한 폴더에 있는 내용을 모두 웹 서버 루트 폴더에 올린다.
- 따라서 img 태그의 src 속성에 "/public"이 아닌 바로 이미지 파일명을 입력하여 사용했다.
- 지정한 이미지 파일이 출력된 것을 확인할 수 있다.
- router 미들웨어는 페이지 라우팅을 구현하는 미들웨어이다.
- 페이지 라우팅은 클라이언트 요청에 적절한 페이지를 제공하는 기술이다.
- app.router 속성을 사용하고 다른 미들웨어와 다르게 express 객체에 들어있는 것이 아니고 함수를 호출하는 것이 아니다.
- get(path, callback) GET 요청이 발생했을 때의 이벤트 리스너를 지정한다.
- post(path, callback) POST 요청이 발생했을 때의 이벤트 리스너를 지정한다.
- put(path, callback) PUT 요청이 발생했을 때의 이벤트 리스너를 지정한다.
- del(path, callback) DELETE 요청이 발생했을 때의 이벤트 리스너를 지정한다.
- all(path, callback) 모든 요청이 발생했을 때의 이벤트 리스너를 지정한다.
- http://127.0.0.1:52273/a 로 접근했을 때의 화면이다.
- http://127.0.0.1:52273/b 로 접근했을 때의 화면이다.
- http://127.0.0.1:52273/a 와 http://127.0.0.1:52273/b 로 접근했을 때 출력된 로그이다.
- get() 메서드의 첫 번째 매개변수에 문자열 /:id 를 입력했다.
- http://127.0.0.1:52273/page/273 에 접속하면 id 속성에 273을 입력했으므로 '273 Page'를 출력한다.
- http://127.0.0.1:52273/index 이외의 요청은 모두 에러를 출력한다.
- http://127.0.0.1:52273/index 로 접근했을 때의 화면이다.
- http://127.0.0.1:52273/index 이외에 다른 주소로 접근했을 때의 오류 화면이다. ex) http://127.0.0.1:52273/test
- cookie parser 미들웨어는 요청 쿠키를 추출하는 미들웨어이다.
- cookie parser 미들웨어를 사용하면 request 객체에 cookies 속성이 부여된다.
- require('cookie-parser') 를 사용하기 위해서는 모듈을 설치해야 한다.
[ 코드 - cookie parser 미들웨어를 사용한 쿠키 추출 ]
//모듈을 추출한다.
var http = require('http');
var express = require('express');
var cookieParser = require('cookie-parser'); //express 4.x부터 express.cookieParser()가 사용되지 않으므로 이것으로 사용한다.
//서버를 생성한다.
var app = express();
//app.use(app.router); //express 4.x부터 사용되지 않는다.
app.use(cookieParser()); //express 4.x부터 express.cookieParser()가 사용되지 않으므로 이것으로 사용한다.
//라우터를 설정한다.
app.get('/getCookie', function (request, response) {
//응답한다.
response.send(request.cookies);
});
app.get('/setCookie', function (request, response) {
//쿠키를 생성한다.
response.cookie('string', 'cookie');
response.cookie('json', {
name: 'cookie',
property: 'delicious'
});
//응답한다.
response.redirect('/getCookie');
});
//서버를 실행한다.
http.createServer(app).listen(52273, function () {
console.log('Server running at http://127.0.0.1:52273');
});
- http://127.0.0.1:52273/setCookie 로 접속하면 string 쿠키와 json 쿠키를 생성한다.
- 이어서 redirect로 getCookie로 자동 이동한다.
- httpOnly : 클라이언트의 쿠키 접근 권한을 지정한다.
- secure : secure 속성을 지정한다.
- expires : expires 속성을 지정한다.
- maxAge : 상대적으로 expires 속성을 지정한다.
- path : path 속성을 지정한다.
9. body parser 미들웨어
- POST 요청 데이터를 추출하는 미들웨어이다.
- body parser 미들웨어를 사용하면 request 객체에 body 속성이 부여된다.
- express 4.x부터 body parser가 사용되지 않으므로 body-parser 미들웨어를 설치해야 한다.
9.1 입력 양식 데이터 추출
[ 코드 - login.html 파일 ]
<!DOCTYPE html>
<html>
<head>
<title>Login Page</title>
</head>
<body>
<h1>Login Page</h1>
<hr />
<form method="post">
<table>
<tr>
<td><label>Username</label></td>
<td><input type="text" name="login" /></td>
</tr>
<tr>
<td><label>Password</label></td>
<td><input type="password" name="password" /></td>
</tr>
</table>
<input type="submit" name="" />
</form>
</body>
</html>
[ 코드 - 서버 기본 설정 ]
//모듈을 추출한다.
var fs = require('fs');
var http = require('http');
var express = require('express');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//서버를 생성한다.
var app = express();
//미들웨어를 설정한다.
app.use(cookieParser());
//라우터를 설정한다.
app.get('/', function (request, response) { });
app.get('/login', function (request, response) { });
app.post('/login', function (request, response) { });
//서버를 실행한다.
http.createServer(app).listen(52273, function () {
console.log('Server running at http://127.0.0.1:52273');
})
- 이어서 GET 방식으로 여청했을 경우 POST 방식으로 요청했을 경우 두 가지로 나누어 GET 방식일 때는 HTML 페이지를 추출하고 POST 방식일 때는 클라이언트가 입력한 아이디와 비밀번호를 확인하여 auth 쿠키를 생성하는 것을 만들어보자.
- Username 과 Password에 아무 글자나 입력하면 다시 로그인 화면으로 돌아온다.
- Username에 rint 를, password에 1234 를 입력하고 [제출] 버튼을 클릭한다.
[ 실행 - 로그인 성공 화면 ]
- 일반적인 입력 양식은 application/x-www-from-urlencoded 인코딩 방식을 사용한다.
- 파일은 일반적인 입력 양식 데이터에 비해 용량이 크다. 따라서 웹 브라우저는 파일을 전송할 때 multipart/form-data 인코딩 방식을 사용한다.
- express 4.x부터 multipart 미들웨어가 제거되어 bodyParser 미들웨어의 multipart 기능이 불가능해졌다.
- 그렇기 때문에 대체수단으로 connect-multipart 미들웨어를 설치한다.
- 반드시 <form> 태그의 enctype 속성을 "multipart/form-data"로 지정해야 한다.
[ 실행 - 파일 업로드 ]
[ 실행 - 파일 업로드 ]
- 업로드한 파일의 정보가 출력된다.
[ 코드 - 파일 이름 변경 및 제거 ]
//모듈을 추출한다.
var fs = require('fs');
var http = require('http');
var express = require('express');
var multiparty = require('connect-multiparty'); //express 4.x 부터 express 모듈의 multipart 미들웨어가 제거되었다. 따라서 bodyParser 미들웨어에서 multipart 기능(업로드와 form-data 파싱)이 불가능해져서 이 미들웨어를 설치하여 사용한다.
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//서버를 생성한다.
var app = express();
//미들웨어를 설정한다.
app.use(cookieParser());
app.use(multiparty());
app.use(express.static('public'));
//app.use(express.limit('10mb')); //express 4.x 부터 사용되지 않는다. 아래 문장처럼 사용할 것.
app.use(bodyParser.json({ limit : '10mb' }));
app.use(bodyParser({ uploadDir : __dirname + '/multipart' }));
//app.use(app.router); //express 4.x 부터 사용되지 않는다. 바로 get() 또는 post()로 사용한다.
//라우터를 설정한다.
app.get('/', function (request, response) {
fs.readFile('HTMLPage.html', function (error, data) {
response.send(data.toString());
});
});
app.post('/', function (request, response) {
var comment = request.param('comment');
var imageFile = request.files.image;
if (imageFile) {
//변수를 선언한다.
var name = imageFile.name;
var path = imageFile.path;
var type = imageFile.type;
//이미지 파일 확인
if (type.indexOf('image') != -1) {
//이미지 파일의 경우: 파일의 이름을 변경한다.
var outputPath = __dirname + '/multipart/' + Date.now() + '_' + name;
fs.rename(path, outputPath, function (error) {
response.redirect('/');
});
} else {
//이미지 파일이 아닌 경우: 파일 이름을 제거한다.
fs.unlink(path, function (error) {
response.send(400);
});
}
} else {
//파일이 없을 경우
response.send(404);
}
});
//서버를 실행한다.
http.createServer(app).listen(52273, function () {
console.log('Server running at http://127.0.0.1:52273');
});
- 파일 업로드 할 때 파일명이 같은 경우 덮어 씌워지게 된다. 따라서 파일명을 확인하여 중복되지 않도록 하고자 한다.
- rename() 메서드를 사용해 시간을 기반으로 파일의 이름을 변경한다.(이 방식이 100% 중복을 막을 수 없으나 예제로 하겠다.)
- 또한 이미지 파일이 아니라면 파일을 제거한다.
- 웹브라우저로 실행하여 파일을 업로드하면 multipart 디렉터리에 "날짜_파일명.확장자"와 같은 형식으로 이름이 바뀌어 업로드된 것을 확인할 수 있다.
10. session 미들웨어
- 쿠키(cookie)는 정보를 클라이언트의 PC에 저장하고 세션(session)은 정보를 서버에 저장하는 기술이다.
- 세션은 클라이언트에 세션 식별자 쿠키를 부여한다.
- 부여한 세션 식별자 쿠키와 대응되는 서버에 위치하는 별도 저장소에 데이터를 저장한다.
- session 미들웨어는 세션을 쉽게 생성할 수 있게 도와주는 미들웨어이다.
- session 미들웨어를 사용하면 request 객체에 session 속성을 부여한다.
- session 미들웨어는 자체적으로 cookie parser 미들웨어를 사용하므로 cookie-parser 미들웨어와 session 미들웨어가 순서대로 추가되어야 한다.
- express 4.x부터 express.session()이 지원되지 않으므로 cookie-session 미들웨어를 설치한다.
[ cookie-session 미들웨어 설치 ]
$ npm install cookie-session
[ 코드 - session 미들웨어 ]
//모듈을 추출한다.
var http = require('http');
var express = require('express');
var cookieParser = require('cookie-parser');
var session = require('cookie-session');
var bodyParser = require('body-parser');
//서버를 실행한다.
var app = express();
//미들웨어를 설정한다.
app.use(cookieParser());
app.use(session({ secret: 'secret key' }));
app.use(bodyParser());
app.use(function (request, response) {
//변수를 선언한다.
var output = {};
output.cookies = request.cookies;
output.session = request.session;
//세션을 저장한다.
request.session.now = (new Date()).toUTCString();
//응답한다.
response.send(output);
});
//서버를 실행한다.
http.createServer(app).listen(52273, function () {
console.log('Server running at http://127.0.0.1:52273');
});
[ 실행 - 처음 접속 ]
- session에 저장된 내용만 출력된다. cookie 정보는 다시 접속했을 때 나타나게 된다.
[ 실행 - 두 번째 접속 ]
- 다시 접속하면 cookies의 express:sess.sig 쿠키가 생성된 것을 확인할 수 있다. 이것은 쿠키로 서버에 저장된 데이터를 확인한다.
- 브라우저를 종료하고 다시 실행하면 express:sess.sig 쿠키가 소멸되므로 클라이언트는 자신이 소유한 정보를 잃게 된다.
- session의 이름과 유지하는 시간을 바꾸어보자.
[ session() 메서드의 옵션 ]
- key : 쿠키의 name 속성을 지정한다.
- store : 세션 저장소를 지정한다.
- cookie : 생성할 cookie와 관련된 정보를 지정한다.
[ cookie 속성을 입력하지 않으면 다음과 같은 객체가 입력된다.
{ path: '/', httpOnly: true, maxAge: null }
[ session 객체의 메서드 ]
- regenerate() : 세션을 다시 생성한다.
- destroy() : 세션을 제거한다.
- reload() : 세션을 다시 불러온다.
- save() : 세션을 저장한다.
11. RESTful 웹 서비스 개발
- RESTful 웹 서비스는 REST(REpresentational Status Transfer) 규정에 맞춰 만든 웹 서비스를 의미한다.
- REST 규정이란?
- 일관된 웹 서비스 인터페이스 설계를 위한 규정이다.
경로 | /collection |
collection |
GET 방식 |
컬렉션을 조회한다. |
컬렉션의 특정 요소를 조회한다. |
POST 방식 |
컬렉션에 새로운 데이터를 추가한다. |
사용하지 않는다. |
PUT 방식 |
컬렉션 전체를 한꺼번에 변경한다. |
컬렉션에 특정 요소를 수정한다. |
DELETE 방식 |
컬렉션 전체를 삭제한다. |
컬렉션의 특정 요소를 삭제한다. |
- GET /user - 사용자 전체를 조회한다.
- GET /user/273 - 273번 사용자를 조회한다.
- POST /user - 사용자를 추가한다.
- DELETE /user/273 - 273번 사용자를 삭제한다.
라우트 |
경로 |
설명 |
GET |
/user |
모든 사용자 정보를 조회한다. |
GET |
/user/:id |
특정 사용자 정보를 조회한다. |
POST |
/user |
사용자를 추가한다. |
PUT |
/user/:id |
특정 사용자 정보를 수정한다. |
DELETE |
/user/:id |
특정 사용자 정보를 제거한다. |
11.1 더미 데이터베이스 구현
- 데이터를 저장하려면 데이터 저장소가 필요하다.
- 일반적으로 MySQL 같은 데이터베이스를 사용하지만 아직 배우지 않았으므로 더미 데이터베이스라는 가상의 데이터베이스를 만들어서 사용하자.
- get() 메서드
- 데이터를 조회하는 메서드이다.
- 매개변수 id를 넣고 호출하면 특정 데이터 하나를 선택해서 리턴한다.
- 반면 id를 넣지 않고 호출하면 모든 데이터를 리턴한다.
- insert() 메서드
- 데이터를 추가하는데 사용한다.
- 데이터에 id 속성을 추가하고 storage 배열에 넣는다.
- 모든 처리가 정상적으로 완료되면 자기 자신을 리턴한다.
- remove() 메서드
- 데이터를 제거하는 메서드이다.
- 배열의 splice() 메서드를 사용해 특정 데이터를 제거한다.
11.2 GET 요청
[ 코드 - GET 요청 ]
app.get('/user', function (request, response) {
response.send(DummyDB.get());
});
app.get('/user/:id', function (request, response) {
response.send(DummyDB.get(request.param('id')));
});
- 모든 사용자를 조회하는 것과 특정 사용자를 조회하는 것을 구현한 것이다.
- http://127.0.0.1:52273/user 에 접속한다. 아직 데이터를 넣지 않았으므로 아무 데이터도 출력되지 않는다.
11.3 POST 요청
[ 코드 - POST 요청 ]
app.post('/user', function (request, response) {
//변수를 선언한다.
var name = request.param('name');
var region = request.param('region');
//유효성을 검사한다.
if (name && region) {
response.send(DummyDB.insert({
name: name,
region: region
}));
} else {
throw new Error('error');
}
});
- 입력 양식으로부터 전달된 name 속성과 region 속성을 추출하고 더미 데이터베이스에 추가한다.
[ 실행 - POST 요청 ]
- 크롬 확장프로그램인 Postman 으로 실행한 모습이다.
- 어떤 이유인지는 알 수 없으나 [form-data]로 하면 에러가 발생된다. 이부분 때문에 몇일동안 검색도 많이 해봤으나 해결하진 못했다.
- [x-www-form-urlencoded]로 선택하여 진행하면 정상적으로 나온다. 파라미터 값에 한글을 입력한 것도 아닌데 왜 urlencode로 넘겨야 정상적으로 작동하는 것인지 이유는 모르겠다. ㅜ_ㅜ;;;
- name, region, id 값이 정상적으로 DummyDB에 등록되어 화면에 출력된 모습을 볼 수 있다.
11.4 PUT 요청
- id 속성과 name 속성, region 속성을 추출하고 더미 데이터베이스에서 데이터를 추출해 수정한다.
[ 실행 - PUT 요청 ]
- 앞서 POST 요청에서처럼 테스트한 뒤 PUT 요청을 사용하여 DummyDB를 수정해본다.
[ 실행 - DELETE 요청 ]
- id가 1인 데이터에 대해 삭제를 하였다.
'Node.js' 카테고리의 다른 글
Node.js express 4.x 프레임워크 설치 및 실행 (0) | 2016.02.11 |
---|---|
Node.js 외부 모듈 (0) | 2014.11.12 |
Node.js http 모듈 (0) | 2014.11.05 |
Node.js 이벤트 (0) | 2014.07.06 |
Node.js 기본 내장 모듈 (2) | 2014.06.29 |