http
모듈을 사용한다.http.createServer([requestListener])
는 http.Server
의 새로운 인스턴스를 반환한다.requestListener
는 request
이벤트가 발생했을 때 자동으로 호출될 콜백 함수이다.Server
인스턴스는 listen
메소드를 호출하여 접속 대기를 시작한다.// server.js
// Node.js에 기본 내장되어 있는 http 모듈을 로드한다
var http = require("http");
// http 모듈의 createServer 메소드를 호출하여 HTTP 서버 생성
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"}); // (1)
response.write("Hello World"); // (2)
response.end(); // (3)
}).listen(8888);
var http = require("http");
const onRequest = (request, response) => {
console.log("request received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("hello world!");
response.end();
};
http.createServer(onRequest).listen(8888);
// server.js
var http = require("http");
const start = () => {
const onRequest = (request, response) => {
console.log("request received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("hello world!");
response.end();
};
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
exports.start = start;
// index.js
var server = require("./server");
server.start();
// url & querystring modules
url.parse(string).query
|
url.parse(string).pathname |
| |
| |
----- -------------------
http://localhost:8888/start?foo=bar&hello=world
--- -----
| |
| |
querystring.parse(string)["foo"] |
|
querystring.parse(string)["hello"]
url
모듈 : URL의 각 부분을 추출할 수 있는 메소드를 제공querystring
모듈 : query string을 request 파라미터로 파싱, POST 요청의 body를 파싱하는 데 사용var http = require("http");
var url = require("url");
const start = () => {
const onRequest = (request, response) => {
var pathname = url.parse(request.url).pathname;
console.log("Path name is " + pathname);
var query = url.parse(request.url, true).query;
console.log("Request param is : ", query);
response.writeHead(200, {"Content-Type": "text/html"});
response.write("<h1>Path name is "+ pathname + "</h1>" +
"<h1>Request param is "+ JSON.stringify(query) + "</h1>");
response.end();
};
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
exports.start = start;
url
모듈을 사용하여 URL path를 기준으로 요청을 구분할 수 있다. // router.js
const route = pathname => {
console.log("About to route a request for "+ pathname);
};
exports.route = route;
// server.js
var http = require("http");
var url = require("url");
const start = route => {
const onRequest = (request, response) => {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(pathname);
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
};
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
exports.start = start;
// index.js
var server = require("./server");
var router = require("./router");
server.start(router.route);
url
모듈로 추출한 값을 해당 함수에 넘겨준다.Request handler
를 만들어 path에 따라 핸들러 내 다른 함수를 호출할 수 있도록 해보자.// requestHandler.js
exports.start = () => {
console.log("request handler 'start' was called");
return "Hello Start";
}
exports.upload = () => {
console.log("request handler 'upload' was called");
return "Hello Upload"
}
// index.js
var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");
var handle = {};
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
server.start(router.route, handle);
// server.js
var http = require("http");
var url = require("url");
const start = (route, handle) => {
const onRequest = (request, response) => {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(route(handle, pathname));
response.end();
};
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
exports.start = start;
// router.js
const route = (handle, pathname) => {
console.log("About to route a request for "+ pathname);
if (typeof handle[pathname] === 'function') {
return handle[pathname]();
} else {
console.log("No request handler found for "+ pathname);
return "404 NOT FOUND"
}
};
exports.route = route;
사실 위의 코드는 requestHandler
에 비동기 방식의 코드를 포함시키면 문제가 발생한다.
Node.js는 이벤트 기반 비동기 방식으로 작동한다.
동기방식 코드를 비동기로 전환하는 방법에는 다음과 같은 두가지가 있다.
requestHandler
에 비동기 방식의 코드를 포함시켜보자.
const { exec } = require("child_process");
const { stderr } = require("process");
exports.start = () => {
console.log("request handler 'start' was called");
var content = "empty";
exec("ls -lah", (error, stdout, stderr) => {
content = stdout;
})
return content;
}
exports.upload = () => {
console.log("request handler 'upload' was called");
return "Hello Upload"
}
exec
은 non-blocking 방식으로 동작한다.exec
을 호출한 후 결과를 기다리지 않고 바로 return content;
를 실행하는 것이다.지금까지 content는 다음과 같이 이동하였다.
새로운 방법에서는 이동 방향을 역으로 전환할 것이다.
즉, http.createServer
의 callback인 onRequest()에서 얻은 response
객체를 router
를 통해 requestHandler
에게 주입한다.
// server.js
var http = require("http");
var url = require("url");
exports.start = (route, handle) => {
const onRequest = (request, response) => {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(handle, pathname, response);
};
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
// router.js
exports.route = (handle, pathname, response) => {
console.log("About to route a request for "+ pathname);
if (typeof handle[pathname] === 'function') {
return handle[pathname](response);
} else {
console.log("No request handler found for "+ pathname);
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("404 NOT FOUND");
response.end();
}
};
// requestHandlers.js
const { exec } = require("child_process");
const { stderr } = require("process");
exports.start = response => {
console.log("request handler 'start' was called");
exec("ls -lah", (error, stdout, stderr) => {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(stdout);
response.end();
})
}
exports.upload = response => {
console.log("request handler 'upload' was called");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello Upload");
response.end();
}
request.addListener(eventName, callback)
data
이벤트 : POST 데이터의 새 청크가 도착했다.end
이벤트 : 모든 청크를 다 받았다.request.addListener
대신 request.on
도 가능하다.// server.js
var http = require("http");
var url = require("url");
exports.start = (route, handle) => {
const onRequest = (request, response) => {
var postData = "";
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
request.setEncoding("utf8");
request.addListener("data", postDataChunk => {
postData += postDataChunk;
console.log("Received POST data chunk '"+ postDataChunk +"'.")
})
request.addListener("end", () => {
route(handle, pathname, response, postData);
})
};
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
// router.js
exports.route = (handle, pathname, response, postData) => {
console.log("About to route a request for "+ pathname);
if (typeof handle[pathname] === 'function') {
return handle[pathname](response, postData);
} else {
console.log("No request handler found for "+ pathname);
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("404 NOT FOUND");
response.end();
}
};
// requestHandler.js
const { exec } = require("child_process");
const { stderr } = require("process");
exports.start = response => {
console.log("request handler 'start' was called");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" content="text/html; '+
'charset=UTF-8" />'+
'</head>'+
'<body>'+
'<form action="/upload" method="post">'+
'<textarea name="text" rows="20" cols="60"></textarea>'+
'<input type="submit" value="Submit text" />'+
'</form>'+
'</body>'+
'</html>';
exec("ls -lah", (error, stdout, stderr) => {
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
})
}
exports.upload = (response, postData) => {
console.log("request handler 'upload' was called");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("You've sent: "+postData);
response.end();
}