1. 서버 객체에서 사용할 수 있는 대표적인 메소드
메소드 이름 |
설명 |
listen(port [,hotsname][,backlog][,callback]) |
서버를 실행하여 대기 |
close([callback]) |
서버를 종료 |
2. 서버 객체의 주요 이벤트
이벤트 이름 |
설명 |
connection |
클라이언트가 접속하여 연결이 만들어 질 때 발생하는 이벤트 |
request |
클라이언트가 요청할 때 발생하는 이벤트 |
close |
서버를 종료할 때 발생하는 이벤트 |
3. 응답 객체의 주요 메소드
메소드 이름 |
설명 |
writeHead(statusCode [, statusMessage][, headers]) |
응답으로 보낼 헤더를 만듭니다. |
write(chunk [, encoding][, callback]) |
응답 본문(body) 데이터를 만듭니다. 여러번 호출 |
end([data][, encoding][, callback]) |
클라이언트로 응답을 전송합니다. 파라미터에 데이터가 들어있다면 이 데이터를 포함시켜 응답을 전송합니다. 클라이언트의 요청이 있을 때 한번은 호출되어야 응답을 보내며, 콜백 함수가 지정되면 응답이 전송된 후 콜백 함수가 호출됩니다. |
var http = require('http'); // 웹서버 객체를 만듭니다. var server = http.createServer(); // 웹서버를 시작하여 7001번 포트에서 대기하도록 합니다. var port = 7001; server.listen(port, function() { console.log('웹서버가 시작되었습니다. : %d', port); }); // 클라이언트 연결 이벤트 처리 server.on('connection', function(socket) { console.log('클라이언트가 접속했습니다. : %s, %d', socket.remoteAddress, socket.remotePort); }); // 클라이언트 요청 이벤트 처리 server.on('request', function(req, res) { console.log('클라이언트 요청이 들어왔습니다.');
res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"}); res.write("<!DOCTYPE html>"); res.write("<html>"); res.write(" <head>"); res.write(" <title>응답 페이지</title>"); res.write(" </head>"); res.write(" <body>"); res.write(" <h1>노드제이에스로부터의 응답 페이지</h1>"); res.write(" </body>"); res.write("</html>"); res.end();
}); /* var server = http.createServer(function(req, res) { console.log('클라이언트 요청이 들어왔습니다.');
res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"}); res.write("<!DOCTYPE html>"); res.write("<html>"); res.write(" <head>"); res.write(" <title>응답 페이지</title>"); res.write(" </head>"); res.write(" <body>"); res.write(" <h1>노드제이에스로부터의 응답 페이지</h1>"); res.write(" </body>"); res.write("</html>"); res.end(); }); // 이걸로 대체가능 */ // 서버 종료 이벤트 처리 server.on('close', function() { console.log('서버가 종료됩니다.'); }); |
|
var http = require('http'); var fs = require('fs'); // 웹서버 객체를 만듭니다. var server = http.createServer(); // 웹서버를 시작하여 3000번 포트에서 대기하도록 합니다. var port = 7001; server.listen(port, function() { console.log('웹서버가 시작되었습니다. : %d', port); }); // 클라이언트 연결 이벤트 처리 server.on('connection', function(socket) { console.log('클라이언트가 접속했습니다. : %s, %d', socket.remoteAddress, socket.remotePort); }); // 클라이언트 요청 이벤트 처리 server.on('request', function(req, res) { console.log('클라이언트 요청이 들어왔습니다.');
var filename = 'house.png'; var infile = fs.createReadStream(filename, {flags: 'r'} ); var filelength = 0; var curlength = 0;
fs.stat(filename, function(err, stats) { filelength = stats.size; });
// 헤더 쓰기 res.writeHead(200, {"Content-Type": "image/png"}); // 파일 내용을 스트림에서 읽어 본문 쓰기 infile.on('readable', function() { var chunk; while (null !== (chunk = infile.read())) { console.log('읽어들인 데이터 크기 : %d 바이트', chunk.length); curlength += chunk.length; res.write(chunk, 'utf8', function(err) { console.log('파일 부분쓰기 완료 : %d, 파일 크기 : %d', curlength, filelength); if (curlength >= filelength) { // 응답 전송하기 res.end(); } }); } });
// 파이프로 연결하여 알아서 처리되도록 하기 //infile.pipe(res);
}); // 서버 종료 이벤트 처리 server.on('close', function() { console.log('서버가 종료됩니다.'); }); |
|
4. Content-Type에 설정할 수 있는 대표적인 MIME Type
Cotent Type 값 |
설명 |
text/plain |
일반 텍스트 문서 |
text/html |
html문서 |
text/css |
css문서 |
text/xml |
xml문서 |
image/jpeg, image/png |
jpeg 파일, png파일 |
video/mpeg, audio/mp3 |
mpeg 비디오 파일, mp3 음악 파일 |
application/zip |
zip 압축 파일 |
5. require(./폴더이름)
폴더이름 지정시 그 폴던안에있는 index.js파일을 불러옴
- express() 메소드를 호출하여 만든 app 객체의 주요 메소드
메소드 이름 |
설명 |
set(name, value) |
서버 설정을 위한 속성을 지정합니다. set() 메소드로 지정한 속성은 get() 메소드로 꺼내어 확인할 수 있다. |
get(name) |
서버 설정을 위해 지정한 속성을 꺼내 온다. |
use([path,] function [,function..]) |
미들웨어 함수를 사용 |
get([path,] function) |
특정 패스로 요청된 정보를 처리 |
- 서버 설정을 위해 미리 정해진 app 객체의 주요 속성
속성 이름 |
설명 |
env |
서버 모드를 설정 |
views |
뷰들이 들어 있는 폴더 또는 폴더 배열을 설정 |
view engine | 디폴트로 사용할 뷰 엔진을 설정 |
- Express()에서 추가로 사용할 수 있는 응답 객체의 메소드
메소드 이름 |
설명 |
send([body]) |
클라이언트에 응답 데이터를 보낸다. 전달할 수 있는 데이터는 HTML문자열, buffer객체, json객체, json 배열 |
status(code) |
http상태코드를 반환. 상태 코드는 end()나 send() 같은 전송 메소드를 추가로 호출해야 전송 |
sendStatus(statusCode) |
http 상태 코드를 반환. 상태코드는 상태메시지와 함께 전송 |
redirect([status,] path) |
웹페이지 경로를 강제로 이동 |
render(view, [,locals][,callback]) |
뷰 엔진을 사용해 문서를 만든 후 전송 |
param(name) |
요청 파라미터를 확인 |
header(name) | 헤더를 확인 |
- static 미들웨어 : 특정 폴더의 파일들을 특정 패스로 접근할 수 있도록 만들어 준다.
ex) app.use(express.static(path.join(__dirname, 'public')));
이렇게 작성하면 public 폴더안에있는 html, png, js, css등에 접근이 가능
- body-parser 미들웨어 : POST로 요청했을 떄 요청 파라미터를 확인이 가능.
ex) var paramPassword = req.body.password || req.query.password; var paramId = req.body.id || req.query.id; |
- routher 미들웨어 : 익스프레스에 미리 등록되어있어 바로 사용이 가능
라우터 미들웨어를 사용할려면 app객체 메소드로 이용하면됨 ex) app.post('요청 URL', function(req,res){ var id = req.param('id'); var pwd = req.param('pwd'); res.writeHead(....); res.write(.....); ..... res.end() }); |
메소드 이름 |
설명 |
get(path, callback) |
get방식으로 특정 패스 요청이 발생했을 때 사용할 콜백 함수를 지정 |
post(path, callback) |
post방식... 이하 동일 |
put(path, callback) |
put방식... 이하 동일 |
delete(path, callback) |
delete방식... 이하 동일 |
all(path, callback) |
모든 요청 방식을 처리하며, 특정 패스 요청이 발생했을 때 사용할 콜백 함수를 지정 |
- URL 파라미터 사용
URL 뒤에 ? 기호를 붙이면 필요에 따라 요청 파라미터(query string)를 추가하여 보낼 수 있다.
/process/login -> /process/login/:name
를 쓰면 var paramName = req.params.name; 로 긁어 올수 있다.
- 오류 페이지 보여주기
// 등록되지 않은 패스에 대해 페이지 오류 응답 app.all('*', function(req, res) { res.status(404).send('<h1>ERROR - 페이지를 찾을 수 없습니다.</h1>'); }); |
- express-error-handler 미들웨어로 오류 페이지 보여주기
// 에러 핸들러 모듈 사용 var expressErrorHandler = require('express-error-handler'); // 404 에러 페이지 처리 var errorHandler = expressErrorHandler({ static: { '404': './public/404.html' } }); app.use( expressErrorHandler.httpError(404) ); app.use( errorHandler ); |
6. 로그인 예제
// Express 기본 모듈 불러오기 var express = require('express') , http = require('http') , path = require('path'); // Express의 미들웨어 불러오기 var bodyParser = require('body-parser') , cookieParser = require('cookie-parser') , serveStatic = require('serve-static'); // 에러 핸들러 모듈 사용 var expressErrorHandler = require('express-error-handler'); // Session 미들웨어 불러오기 var expressSession = require('express-session'); // 익스프레스 객체 생성 var app = express(); // 기본 속성 설정 app.set('port', process.env.PORT || 7001); // body-parser를 이용해 application/x-www-form-urlencoded 파싱 app.use(bodyParser.urlencoded({ extended: false })) // body-parser를 이용해 application/json 파싱 app.use(bodyParser.json()) app.use('/public', serveStatic(path.join(__dirname, 'public'))); // cookie-parser 설정 app.use(cookieParser()); // 세션 설정 app.use(expressSession({ secret:'my key', resave:true, saveUninitialized:true })); // 라우터 사용하여 라우팅 함수 등록 var router = express.Router(); // 로그인 라우팅 함수 - 로그인 후 세션 저장함 router.route('/process/login').post(function(req, res) { console.log('/process/login 호출됨.'); var paramId = req.body.id || req.query.id; var paramPassword = req.body.password || req.query.password;
if (req.session.user) { // 이미 로그인된 상태 console.log('이미 로그인되어 상품 페이지로 이동합니다.');
res.redirect('/public/product.html'); } else { // 세션 저장 req.session.user = { id: paramId, name: '소녀시대', authorized: true };
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'}); res.write('<h1>로그인 성공</h1>'); res.write('<div><p>Param id : ' + paramId + '</p></div>'); res.write('<div><p>Param password : ' + paramPassword + '</p></div>'); res.write("<br><br><a href='/process/product'>상품 페이지로 이동하기</a>"); res.end(); } }); // 로그아웃 라우팅 함수 - 로그아웃 후 세션 삭제함 router.route('/process/logout').get(function(req, res) { console.log('/process/logout 호출됨.');
if (req.session.user) { // 로그인된 상태 console.log('로그아웃합니다.');
req.session.destroy(function(err) { if (err) {throw err;}
console.log('세션을 삭제하고 로그아웃되었습니다.'); res.redirect('/public/login2.html'); }); } else { // 로그인 안된 상태 console.log('아직 로그인되어있지 않습니다.');
res.redirect('/public/login2.html'); } }); // 상품정보 라우팅 함수 router.route('/process/product').get(function(req, res) { console.log('/process/product 호출됨.');
if (req.session.user) { res.redirect('/public/product.html'); } else { res.redirect('/public/login2.html'); } }); app.use('/', router); // 404 에러 페이지 처리 var errorHandler = expressErrorHandler({ static: { '404': './public/404.html' } }); app.use( expressErrorHandler.httpError(404) ); app.use( errorHandler ); // Express 서버 시작 http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); }); |
|
- 주의사항 : 미들웨어 사용하는 순서가 바뀌면 오류가 날 수 있다.
파일 업로드 기능을 구현할 떄 body-parser, multer, router 등의 미들웨어를 사용하는데 여러개의 미들웨어를 사용시 사용순서가 바뀌면 제대로 동작되지 않는다.
- multer 미들웨어를 사용할 떄 설정하는 주요 속성과 메소드
속성/메소드 이름 |
설명 |
dest |
업로드한 파일들이 저장도리 폴더를 지정 |
putSingleFilesInArray |
응답 객체의 files 속성에 업로드한 파일 정보를 클라이언트 요청 이름으로 넣을 때, 파일이 한 개라도 배열 형태로 넣을 것인지를 지정 |
limits |
파일 크기나 파일 개수 등의 제한 속성을 설정하는 객체 |
rename(fieldname, filename, req, res) |
업로드한 파일의 이름을 바꿈 |
onFileUploadStart(file, req, res) |
파일 업로드가 시작될 때 호출 |
onFileUploadComplete(file, req, res) |
파일 업로드가 완료되었을 때 호출 |
onFileSizeLimit(file) |
limits 객체에 설정한 제한을 넘어섰을 떄 호출 |
7. 파일 업로드
// Express 기본 모듈 불러오기 var express = require('express') , http = require('http') , path = require('path'); // Express의 미들웨어 불러오기 var bodyParser = require('body-parser') , cookieParser = require('cookie-parser') , serveStatic = require('serve-static'); // 에러 핸들러 모듈 사용 var expressErrorHandler = require('express-error-handler'); // Session 미들웨어 불러오기 var expressSession = require('express-session'); // 파일 업로드용 미들웨어 var multer = require('multer'); var fs = require('fs'); //클라이언트에서 ajax로 요청 시 CORS(다중 서버 접속) 지원 var cors = require('cors'); // 익스프레스 객체 생성 var app = express(); // 기본 속성 설정 app.set('port', process.env.PORT || 7001); // body-parser를 이용해 application/x-www-form-urlencoded 파싱 app.use(bodyParser.urlencoded({ extended: false })) // body-parser를 이용해 application/json 파싱 app.use(bodyParser.json()) // public 폴더와 uploads 폴더 오픈 app.use('/public', serveStatic(path.join(__dirname, 'public'))); app.use('/uploads', serveStatic(path.join(__dirname, 'uploads'))); // cookie-parser 설정 app.use(cookieParser()); // 세션 설정 app.use(expressSession({ secret:'my key', resave:true, saveUninitialized:true })); //클라이언트에서 ajax로 요청 시 CORS(다중 서버 접속) 지원 app.use(cors()); //multer 미들웨어 사용 : 미들웨어 사용 순서 중요 body-parser -> multer -> router // 파일 제한 : 10개, 1G var storage = multer.diskStorage({ destination: function (req, file, callback) { callback(null, 'uploads') }, filename: function (req, file, callback) { callback(null, file.originalname + Date.now()) } }); var upload = multer({ storage: storage, limits: { files: 10, fileSize: 1024 * 1024 * 1024 } }); // 라우터 사용하여 라우팅 함수 등록 var router = express.Router(); // 파일 업로드 라우팅 함수 - 로그인 후 세션 저장함 router.route('/process/photo').post(upload.array('photo', 1), function(req, res) { console.log('/process/photo 호출됨.');
try { var files = req.files;
console.dir('#===== 업로드된 첫번째 파일 정보 =====#') console.dir(req.files[0]); console.dir('#=====#')
// 현재의 파일 정보를 저장할 변수 선언 var originalname = '', filename = '', mimetype = '', size = 0;
if (Array.isArray(files)) { // 배열에 들어가 있는 경우 (설정에서 1개의 파일도 배열에 넣게 했음) console.log("배열에 들어있는 파일 갯수 : %d", files.length);
for (var index = 0; index < files.length; index++) { originalname = files[index].originalname; filename = files[index].filename; mimetype = files[index].mimetype; size = files[index].size; }
} else { // 배열에 들어가 있지 않은 경우 (현재 설정에서는 해당 없음) console.log("파일 갯수 : 1 ");
originalname = files[index].originalname; filename = files[index].name; mimetype = files[index].mimetype; size = files[index].size; }
console.log('현재 파일 정보 : ' + originalname + ', ' + filename + ', ' + mimetype + ', ' + size);
// 클라이언트에 응답 전송 res.writeHead('200', {'Content-Type':'text/html;charset=utf8'}); res.write('<h3>파일 업로드 성공</h3>'); res.write('<hr/>'); res.write('<p>원본 파일명 : ' + originalname + ' -> 저장 파일명 : ' + filename + '</p>'); res.write('<p>MIME TYPE : ' + mimetype + '</p>'); res.write('<p>파일 크기 : ' + size + '</p>'); res.end();
} catch(err) { console.dir(err.stack); }
});
app.use('/', router); // 404 에러 페이지 처리 var errorHandler = expressErrorHandler({ static: { '404': './public/404.html' } }); app.use( expressErrorHandler.httpError(404) ); app.use( errorHandler ); // Express 서버 시작 http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); }); |
|