[Node.js] 웹 서버 만들기
웹 서버 만들기
노드의 http 모듈을 사용하면 웹 서버 기능을 담당하는 서버 객체를 만들 수 있다.
createServer()
메서드를 이용하여 서버 객체를 만들 수 있다.
//http.createServer() 메서드 이용 서버 객체 생성
var http = require('http')
var server = http.createServer();
// 3000번 포트에서 대기
var port = 3000;
server.listen(port, function(){
console.log('웹 서버 시작 : %d', port);
})
메서드 | 설명 |
---|---|
listen(port, [hostname], [backlog], [callback]) | 서버 실행하여 대기 |
close([callback]) | 서버 종료 |
NOTE: PC나 서버 기계에 이더넷(Ethernet) 카드가 여러개 있는 경우 서버에서 사용할 수 있는 인터넷 주소(IP 주소)가 여러개 존재 하기 때문에 특정 IP주소를 지정하면서 서버를 실행시켜야 할 때도 있다. 이 경우 listen()
메서드를 사용할 때 IP를 직접 지정한다.
//http.createServer() 메서드 이용 서버 객체 생성
var http = require('http')
var server = http.createServer();
// 3000번 포트에서 대기
var host = '172.30.1.14'
var port = 3000;
server.listen(port,host, '50000', function(){
console.log('웹 서버 시작 : %s, %d', host, port);
});
클라이언트가 웹 서버에 요청할 때 발생하는 이벤트 처리하기
웹 브라우저가 웹 서버에 접속한 후 데이터를 요청하면 적절한 이벤트가 발생한다.
그 상황에 맞는 콜백함수를 각각 등록한다.
이벤트이름 | 설명 |
---|---|
connection | 클라이언트가 접속하여 연결될 때 발생하는 이벤트 |
request | 클라이언트가 요청할 때 발생하는 이벤트 |
close | 서버를 종료할 때 발생하는 이벤트 |
//http.createServer() 메서드 이용 서버 객체 생성
var http = require('http')
var server = http.createServer();
// 3000번 포트에서 대기
var port = 3001;
server.listen(port, function(){
console.log('웹 서버 시작 : %d', port);
});
// 클라이언트 연결 이벤트 처리
server.on('connect', function(socket){
var addr = socket.address();
console.log('클라이언트가 접속했습니다. : %s, %d', addr.address, addr.port);
});
// 클라이언트 요청 이벤트 처리
server.on('request', function(req, res){
console.log('클라이언트 요청이 들어왔습니다.');
console.dir(req);
});
// 서버 종료 이벤트 처리
server.on('close', function(){
console.log('서버가 종료됩니다.');
});
웹 서버 시작 : 3001
클라이언트에서 요청이 있을 때 파일 읽어 응답하기
프로젝트 파일에 적당한 이미지를 넣은 후 아래 코드를 이용하여 클라이언트 쪽으로 응답을 보낸다.
server.on('request', function(req, res){
console.log('클라이언트 요청이 들어왔습니다.');
var filename = 'workout.png';
fs.readFile(filename, function(err, data){
if (err) throw err;
res.writeHead(200, {"Content-Type": "image/png"});
res.write(data);
res.end();
});
});
이미지 파일 외에도 일반 텍스트 파일이나 음악 파일 등 같은 방식으로 클라이언트에게 응답할 수 있으며, Content-Type
만 설정해주면된다.
Content-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압출 파일 |
파일스트림으로 읽어 응답 보내기
pipe()
메서드를 이용해 더 쉽게 응답하는 방법
// 계속
server.on('request', function(req, res){
console. log('클라이언트에서 요청이 들어왔습니다.');
var filename = 'workout.png';
var infile = fs.createReadStream(filename, {flags: 'r'});
infile.pipe(res);
});
파일을 버퍼에 담아 두고 일부부만 읽어 응답 보내기
파일을 읽기 전에 파일을 열고, 스트림에서 일정 크기만큼만 읽어 응답을 보내는 방식
응답 객체의 end()
메서드를 호출하는 시점은 write()
메서드가 종료되는 시점이어야 한다.
write()
메서드에 콜백 함수를 전달하여 쓰기가 완료된 시점을 확인한다.
server.on('require', function(req, res){
console.log('클라이언트 요청이 들어왔습니다.');
var filename = 'workout.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();
}
});
}
});
});
서버에서 다른 웹 사이트의 데이터를 가져와 응답하기
서버에서 다른 웹 사이트를 접속하여 데이터를 가져온 후 응답하는 과정이 필요할 수 있다.
서버에서 HTTP클라이언트 기능도 사용하게 될 때, HTTP 클라이언트가 GET
, POST
방식으로 다른 웹 서버에 데이터를 요청할 수 있다.
GET 방식으로 요청
var http = require('http');
var options = {
host: 'www.gogle.com',
port: 80,
path: '/'
}
var req = http.get(options, function(res){
//응답 처리
var resDate = '';
res.on('data', function(chunk){
resDate += chunk;
});
res.on('end', function(){
console.log(resDate);
});
});
req.on('error', function(err){
console.log('오류 발생: ' + err.message);
});
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>
http 객체의 get()
메서드를 이용하여 다른 사이트에 요청을 보내고 응답을 받아 처리했다. options
는 다른 사이트의 정보를 담고있는 객체이며, 응답 데이터는 data
이벤트와 end
이벤트로 처리한다.
POST 방식으로 요청
var http = require('http');
var opts = {
host: 'www.google.com',
port: 80,
method: 'POST',
path: '/',
headers: {}
};
var resData = '';
var req = http.request(opts, function(res){
// 응답 처리
res.on('data', function(chunk){
resData += chunk;
});
res.on('end', function(){
console.log(resData);
});
});
opts.headers['Content-Type'] = 'application/x-www-form-urlencoded';
req.data = "q=workout";
opts.headers['Content-Length'] = req.data.length;
req.on('error', function(err){
console.log('오류발생 : %s', err.message);
});
//요청 전송
req.write(req.data)
req.end();
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
<title>Error 405 (Method Not Allowed)!!1</title>
<style>
*{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
</style>
<a href=//www.google.com/><span id=logo aria-label=Google></span></a>
<p><b>405.</b> <ins>That’s an error.</ins>
<p>The request method <code>POST</code> is inappropriate for the URL <code>/</code>. <ins>That’s all we know.</ins>
요청에 필요한 요청 파라미터는 요청 객체의 data
속성으로 설정한다. data
속성 값에 따라 Content-Length
의 값이 달라지므로, length
메서드를 사용하여 설정해준다. 요청할 때 write()
메서드로 요청 본문 데이터를 req
객체에 쓴 후 end()
메서드로 전송한다. 구글은 POST
방식의 요청을 받지 않으므로 오류가 발생한다.
NOTE: GET 과 POST 방식은 둘다 인터넷 표준으로 정해둔 요청방식(Method)이지만 GET 방식은 헤더 부분에 요청 정보들을 넣어 보내지만 POST 방식은 본문 부분에 요청 정보를 넣어 보낸다. 보안 등의 이슈가 있거나 파일을 요청 정보로 넣어 보내야 하는 경우 POST 방식을 주로 사용한다.
Leave a comment