http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
이게 기본 틀의 예로 볼수 있을듯..
http 서버를 만든거다.
require로 http 모듈을 읽어들이고 그 이후엔 http라는 변수를 통해서 접근을 할수 있다.
http 모듈에서 제공하는 createServer을 호출한다.
listen 함수는 http 서버에서 요청대기할 포트 번호를 나타내는 숫자를 받는다.
createServer의 함수의 파라미터를 함수로 넣고 있는데 자바스크립트에선 함수도 파라미터로 넘길수가 있다.
함수 안의 파라미터 두개 request와 response는 일반적인 웹 에서 사용하는 그 request와, response로 보면 될듯 하고
요청이 들어오면 response.writeHead() 함수를 이용해서 http 200, 너의 요청은 뭐 성공적이다 라는 응답과, content-type 은 text/plain 뭐 일반적인 평문 으로 설정해서 응답 헤더로 보내고
여기다 hello world 텍스트를 응답 바디로 보내는거고 end() 함수로 마무리를 하는 형태이다.
var http = require("http");
function start() {
function 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;
이번엔 우리가 직접 모듈을 만들어 보는거다.
모듈을 만드는건 그냥 export 하면 된다.. 간단하군 크흠...
위에 코드를 보면뭐 주저리 주저리 응답 하는 함수를 start 라는 이름의 함수안에 넣고
아랫줄에 exports.start = start 함수를 연결해 export 해줌..
이 파일을 server.js 라는 이름으로 저장하고 호출 할땐
var server = require("./server");
server.start();
요롷게 .. 우리가만든 모듈 불러오고
걍 start() .. 호우 간단하군.
자 이번엔 라우팅 .. 좀더 요청에 따른 다양한 반응을 하게 하려면 라우팅이 필요하다.
우리가 뭐 웹으로 요청을 보낼때 요청 url이랑, get/post 파라미터를 보통 보내는데.
router는 이것을 전달받으면 어떤 코드를 실행할지 결정을 한다. 즉 router는 요청을 받았을때 실제 일을 하는 request handler이다.
var url = require("url");
function start() {
function 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("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
url 모듈은 url의 각각의 부분을 뽑아낼수 있는 메소드를 제공한다.
request 파라미터로 넘어온 url을 파싱해서 위 코드처럼 접근할수 있다. 이건 일단 server.js 파일.
function route(pathname) {
console.log("About to route a request for " + pathname);
}
exports.route = route;
route라는 함수를 정의한 router.js 파일. 테스트 코드이므로 pathname으로 넘어오는 파라미터를 출력함.
var url = require("url");
function start(route) {
function 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;
http server가 route와 연결하기 위해, start함수에 route를 파라미터로 받는다.
var server = require("./server");
var router = require("./router");
server.start(router.route);
index.js 파일이다.. 음.. 보통 어떤 웹을 공부하든 메인이 되는 파일의 이름은 index 인듯.
본론으로와서. server와, router 모듈을 가져오고
router 함수를 server의 start함수로 파라미터로 보내서 시작한다.
이제 node.js 실행해보면 뭐 .. http server에서 route 사용해서 pathname 넘기는 그런 환경이 구축된거임~ 음 대충 알겟스.
이제는 좀더 확장된 request handler라는 개념을 이용해서 라우팅을 해보기.
function start() {
console.log("Request handler 'start' was called.");
}
function upload() {
console.log("Request handler 'upload' was called.");
}
exports.start = start;
exports.upload = upload;
start 할때는 start() 함수, upload 할때는 upload() 함수.. 다양한 request handler가 들어 있다고 가정하는 requesthandler.js 파일.
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);
메인 파일인 index.js 파일이다.
보면 키/값 쌍으로.. / = requestHandlers.start , /upload = requestHandlers.upload 뭐 이렇게 매핑 시켜주고 server에 파라미터로 route 함수와, handle 을 넘겨주고 있다.
var http = require("http");
var url = require("url");
function start(route, handle) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(handle, 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;
server.js 파일.. start() 함수에서 handle을 받는 파라미터가 추가 되있다.
뭐 봐야할 부분은 route()함수를 호출할때 handle을 파라미터로 추가해서 넘겨준다는거다
function route(handle, pathname) {
console.log("About to route a request for " + pathname);
if (typeof handle[pathname] === 'function') {
handle[pathname]();
} else {
console.log("No request handler found for " + pathname);
}
}
exports.route = route;
router.js 파일.. pathname에 해당하는 request handler가 있는지를 체크하고. 존재하면 해당 함수를 호출한다. 크흠.. 이것도 대충 알겟스.
깨알 추가 팁..은.. 위에 보면 비교 연산자에 === ? 3개다 우리가 보통 보는건 == 이거인데 말이다.
자바스크립트에선 ==, === 이 두개가 개별적으로 있는데 ==는 좀 더.. 느슨하게 비교 한다 하면 될려나 타입에 상관이 뭐 그냥 그 값이 같으면 참인거다.. 문자 0 과 숫자 0을 비교하면 참이 나옴.. 뭐 이런거?
===는 타입이랑 값이 다 똑같아야 참이 나오는거임.. 문자 0이랑 숫자 0 비교하면 거짓 임.. 대충 ㅇㅋ..?
이번엔 node.js의 비동기 방식에 대해서 좀더 알아보기.
console.log("Request handler 'start' was called.");
function sleep(milliSeconds) {
var startTime = new Date().getTime();
while (new Date().getTime() < startTime + milliSeconds);
}
sleep(10000);
return "Hello Start";
}
function upload() {
console.log("Request handler 'upload' was called.");
return "Hello Upload";
}
exports.start = start;
exports.upload = upload;
위에 코드는 비동기가 아니라 동기라고 봐야댄다.. blocking
sleep 함수의 처리때문에 10초 후에 밑의 return 문이 실행된다.
여기서 클라이언트에서 start와, upload 요청 두개가 동시에 들어왔다면 upload 를 로드 하는것도 10초가 걸려버린다 왜냐 start() 함수에서 sleep 때문에 blocking 해버려서 다른 곳에서 일을 못하게 막아버리니 말이다. 우리가 원하는건 이런게 아니지 않겟니? 요청이오면 그에 따른 즉각적인 반응
node.js는 동시작업을 할수 있다. 하지만 쓰레드를 여러개 사용하는것이 아닌 단일 쓰레드 이고 .
event를 통해서 실행하므로 다양한 작업이 동시에 되게 하려면 non-blocking 동작을 사용해야 한다.
function start() {
console.log("Request handler 'start' was called.");
var content = "empty";
exec("ls -lah", function (error, stdout, stderr) {
content = stdout;
});
return content;
}
function upload() {
console.log("Request handler 'upload' was called.");
return "Hello Upload";
}
exports.start = start;
exports.upload = upload;
requestHandler.js 파일.. exec 함수는 비동기 동작을 한다. 뭐 주저리 주저리 함수 실행하고 얻어온 결과값 stdout을 content에 값으로 채우고 return 한다.
그럼 값이 재대로 나오느냐 .. 결론은 아니란다. empty 문자가 그대로 출력된단다 왜 ?
exec 함수를 호출하자마자 코드가 동기적으로 동작해서 node.js는 바로 return content를 실행해버린거다 exec()의 일이 아직 다 처리 되지도 않았는데 말이다.
그럼 이제 한번 비동기적으로 재대로 되게 고쳐본다.
var url = require("url");
function start(route, handle) {
function 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.");
}
exports.start = start;
server.js 파일... route 함수 안에 파라미터로 넘겨주는 값이 추가 됬다. 바로 response 객체를 넘겨주는거다. 이제는 각각의 request handler들이 이 response 객체를 이용해서 응답을 해주는거다!
console.log("About to route a request for " + pathname);
if (typeof handle[pathname] === 'function') {
handle[pathname](response);
} else {
console.log("No request handler found for " + pathname);
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not found");
response.end();
}
}
exports.route = route;
router.js 파일... 해당하는 request handler을 찾지 못하면 직접 응답을 해주고 그게 아니라면 handler 쪽으로 response를 넘겨줌과 동시에 호출한다.
function start(response) {
console.log("Request handler 'start' was called.");
exec("ls -lah", function (error, stdout, stderr) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(stdout);
response.end();
});
}
function upload(response) {
console.log("Request handler 'upload' was called.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello Upload");
response.end();
}
exports.start = start;
exports.upload = upload;
requestHandler.js 파일... handler 함수들이 respone을 파라미터로 받고 요청에 따른 응답을 각각 하고 있다. 이렇게 하고 작동해보면 이제 잘 반응 한다.
아까처럼 중간에 sleep이 잇다고 해도 upload 요청을 해도 바로바로 반응이 된다! 와후
좋았스 일단 기초는 요정도로 알고 가보자.