Node.js 사용 방법

Post date: Mar 29, 2018 2:11:39 AM

[Global Objects]

- global 혹은 GLOBAL 객체를 이용해 전역 변수(global variable) 사용 가능

- console: console 제어, https://nodejs.org/api/console.html

    • Console에 log 표시: console.log()

- process: program과 관련된 정보 획득, https://nodejs.org/api/process.html

    • Node.js version 얻기: console.log(process.version);

    • Memory 사용 현황: console.log(process.memoryUsage());

- module: 사용자 module 만들기, https://nodejs.org/api/modules.html


[Module 만들기]

  • module.exports와 exports의 차이는 구별해야 함

= JS 관점으로 쓰면 다음과 같음: module.exports와 exports는 동일한 empty object를 가르키고 있음

= require()은 해당 file의 module.exports를 가져옴

let module = new Module(); module.exports = {};

let exports = module.exports;


- exports 사용: 여러 개의 method 정의 가능(exports는 기본적으로 module.exports와 동일; exports에는 함수 할당 불가능)

    • circle.js

const PI = Math.PI; // const {PI} = Math;

exports.area = function (r) {

return PI * r * r;

}; // exports.area = (r) => PI*(r**2);

exports.circumference = function (r) {

return 2 * PI * r;

}; // exports.circumference = (r) => 2*PI*r;

    • foo.js

let circle = require('./circle.js');

console.log('The area of a circle of radius 4 is ' + circle.area(4));

= require() 함수를 쓴 경우에 package.json이 있으면 오류 발생: package.json을 지우고 js를 실행해야 함


- module.exports 사용: 하나의 method만 정의 가능(Node.js는 exports보다 module.exports에 우선권을 부여함; module.exports에는 함수 할당 가능)

    • square.js

module.exports = function(width) {

return {

area: function() {

return width * width;

}};

}

    • foo.js

let square = require('./square.js');

let mySquare = square(2);

console.log('The area of my square is ' + mySquare.area());

- Default export 사용: ES6에서만 사용 가능

    • ellipse.js

const PI = Math.PI;

export default function(a, b) {

return {

area: function() {

return PI*a*b;

}

};

};

    • foo.js

import ellipse from './ellipse.js';

let myEllipse = ellipse(2, 3);

console.log(myEllipse.area());

= foo.js가 정상적으로 실행되려면 package.json이 아래와 같이 정의되어야 함

{

"type": "module"

}


- Named export 사용: ES6에서만 사용 가능

    • ellipse.js

const PI = Math.PI;

const sq2 = Math.sqrt(2);

function myFun(a, b) {

return {

area: function() {

return PI*a*b;

}

};

}

export {sq2, myFun};

    • foo.js

import {sq2, myFun} from './ellipse.js';

let myEllipse = myFun(2, 3);

console.log(sq2);

console.log(myEllipse.area());

= foo.js가 정상적으로 실행되려면 package.json이 아래와 같이 정의되어야 함

{

"type": "module"

}


[Node.js Modules]

- os: server가 구동되는 OS 특성 제공, https://nodejs.org/api/os.html

    • 불러오기: const os = require('os');

    • CPU: os.cpus()

- fs: file system 관리 기능 제공, https://nodejs.org/api/fs.html

    • 불러오기: const fs = require('fs');

    • 동기적 file 읽기: let text = fs.readFileSync('text.txt', 'utf8');

    • 비동기적 file 읽기: fs.readFile('text.txt', 'utf8', function (err, data) { console.log(data); let str = data; });

= 동기 읽기에서는 blocking이 있어서 callback이 없음; 반면에 비동기 읽기는 non-blocking이어서 callback이 가능함

= Web server가 구동일 때는 절대 readFileSync()를 쓰지 말고 readFile()을 써야 함

    • 동기적 file 쓰기: let data = 'test'; fs.writeFileSync('text.txt', data, 'utf8');

    • 비동기적 file 쓰기: let data = 'test'; fs.writeFile('text.txt', data, 'utf8', function (err) { console.log('File 쓰기'); });

    • 동기적으로 file이 존재하는지 확인: fs.existsSync('text.txt');

- http: HTTP 함수 제공, https://nodejs.org/api/http.html

- url: URL 함수 제공, https://nodejs.org/api/url.html

- querystring: URL query string 함수 제공, https://nodejs.org/api/querystring.html


  • Node.js에서 위 code를 그대로 실행하면 어떤 경우 "undefined"가 나옴

= 예) node에 들어가서 let a = 1; 이라 쓰면 undefined이 나옴

= "undefined"가 나와도 문제 없음: 이는 명령어 실행 결과의 return이 없다는 의미라서 전혀 문제가 안됨

[단순 Server 구성]

const http = require('http');

// req: request. 웹 요청 매개변수, res: response. 웹 응답 매개변수

server = http.createServer(function (req, res) {

// writeHead: 응답 헤더를 작성합니다.

// 200: 응답 성공, text/html: HTML 문서

res.writeHead(200, {'Content-Type': 'text/html'});

// write & end: 응답 본문을 작성합니다.

res.write('Hello World!');

res.write('<br>Hello ICE!');

res.end(); // res.end('Hello World!<br>Hello ICE!')도 가능

});

// listen: 매개변수로 포트와 호스트를 지정합니다.

server.listen(8000, '127.0.0.1'); // 127.0.0.1 대신 localhost 사용 가능

//server.listen(80, 'localhost'); // 80 port는 HTTP 기본 port

console.log('Server running at http://127.0.0.1:8000');

[ Module 이용한 Server 구성]

- MyServer.js

    • Ver 0.1

const http = require('http');

const sHost = 'localhost';

const nPort = 8000;

function start() {

function onRequest(req, res) {

console.log('Request received.');

res.writeHead(200, { 'Content-Type': 'text/html' });

res.write('Hello World!');

res.write('<br>Hello ICE!');

res.end();

}

http.createServer(onRequest).listen(nPort, sHost);

console.log('Server running at http://' + sHost + ':' + nPort);

}

exports.start = start;

    • Ver 0.2

const http = require('http');

const url = require('url');


const sHost = 'localhost';

const nPort = 8000;

const sBaseUrl = 'http://' + sHost + ':' + nPort;


function start(route) {

function onRequest(req, res) {

console.log('Request received.');

//let sPathname = url.parse(req.url).pathname;

let sPathname = new url.URL(req.url, sBaseUrl).pathname;

console.log('Request for ' + sPathname + ' received.');

route(sPathname);

res.writeHead(200, { 'Content-Type': 'text/html' });

res.write('Hello World!');

res.write('<br>Hello ICE!');

res.end();

}


http.createServer(onRequest).listen(nPort, sHost);

console.log('Server running at http://' + sHost + ':' + nPort);

}

exports.start = start;

    • Ver 0.3

const http = require('http');

const url = require('url');


const sHost = 'localhost';

const nPort = 8000;

const sBaseUrl = 'http://' + sHost + ':' + nPort;


function start(route, handle) {

function onRequest(req, res) {

console.log('Request received.');

let sPathname = new url.URL(req.url, sBaseUrl).pathname;

console.log('Request for ' + sPathname + ' received.');

let content = route(sPathname, handle);

res.writeHead(200, { 'Content-Type': 'text/html' });

res.write(content);

res.end();

}


http.createServer(onRequest).listen(nPort, sHost);

console.log('Server running at http://' + sHost + ':' + nPort);

}

exports.start = start;

    • Ver 0.4

const http = require('http');

const url = require('url');


const sHost = 'localhost';

const nPort = 8000;

const sBaseUrl = 'http://' + sHost + ':' + nPort;


function start(route, handle) {

function onRequest(req, res) {

console.log('Request received.');

let sPathname = new url.URL(req.url, sBaseUrl).pathname;

console.log('Request for ' + sPathname + ' received.');

route(sPathname, handle, res);

}


http.createServer(onRequest).listen(nPort, sHost);

console.log('Server running at http://' + sHost + ':' + nPort);

}

exports.start = start;

    • Ver 0.5

const http = require('http');

const url = require('url');


const sHost = 'localhost';

const nPort = 8000;

const sBaseUrl = 'http://' + sHost + ':' + nPort;


function start(route, handle) {

function onRequest(req, res) {

console.log('Request received.');

let sPathname = new url.URL(req.url, sBaseUrl).pathname;

let sPostData = '';

console.log('Request for ' + sPathname + ' received.');

req.setEncoding('utf8');

req.addListener('data', function (chunk) {

sPostData += chunk;

console.log('chunk: ' + chunk);

});

req.addListener('end', function () {

route(sPathname, handle, res, sPostData);

});

}


http.createServer(onRequest).listen(nPort, sHost);

console.log('Server running at http://' + sHost + ':' + nPort);

}

exports.start = start;

- MyRouter.js

    • Ver 0.2

function route(pathname) {

console.log("Routing a request for " + pathname);

}

exports.route = route;

    • Ver 0.3

function route(pathname, handle) {

console.log("Routing a request for " + pathname);

if (typeof handle[pathname] === 'function') {

return handle[pathname]();

} else {

console.log('No handler for ' + pathname);

return '404 not found';}}

exports.route = route;

    • Ver 0.4

function route(pathname, handle, res) {

console.log("Routing a request for " + pathname);

if (typeof handle[pathname] === 'function') {

handle[pathname](res);

} else {

console.log('No handler for ' + pathname);

res.writeHead(404, { 'Content-Type': 'text/html' });

res.write('404 not found');

res.end();}}

exports.route = route;

    • Ver 0.5

function route(pathname, handle, res, postData) {

console.log("Routing a request for " + pathname);

if (typeof handle[pathname] === 'function') {

handle[pathname](res, postData);

} else {

console.log('No handler for ' + pathname);

res.writeHead(404, { 'Content-Type': 'text/html' });

res.write('404 not found');

res.end();}}

exports.route = route;

- MyHandlers.js

    • Ver 0.3

function start() {

console.log('Request handler \'start\'');

return 'Hello Start!';

}

function hello() {

console.log('Request handler \'hello\'');

return 'Hello Hello!';

}

exports.start = start;

exports.hello = hello;

    • Ver 0.4

function sleep(milliSec) {

let timeStart = new Date().getTime();

while (new Date().getTime() < timeStart + milliSec);

}

function start(res) {

console.log('Request handler \'start\'');

// Blocking function

// sleep(10000);

// Non-blocking function

setTimeout(function () {

res.writeHead(200, { 'Content-Type': 'text/html' });

res.write('Hello Start!');

res.end();

}, 10000); // 10초 기다리고 callback 실행

}

function hello(res) {

console.log('Request handler \'hello\'');

res.writeHead(200, { 'Content-Type': 'text/html' });

res.write('Hello Hello!');

res.end();

}

exports.start = start;

exports.hello = hello;

    • Ver 0.5

const queryString = require('querystring');

function start(res) {

console.log('Request handler \'start\'');

let sBody = '<html>' + '<head>' +

'<meta http-equiv="Content-Type" content="text/html" charset="UTF-8" />' +

'</head>' + '<body>' +

'이름과 별명을 입력하세요.<br>' +

'<form action="/hello" method="post">' +

'<input type="text" name="myName" /><br>' +

'<input type="text" name="myNick" /><br>' +

'<button type="submit">입력 완료</button>' +

'</form>' + '</body>' + '</html>';

res.writeHead(200, { 'Content-Type': 'text/html' });

res.write(sBody);

res.end();

}

function hello(res, postData) {

console.log('Request handler \'hello\'');

let sBody = '<html>' + '<head>' +

'<meta http-equiv="Content-Type" content="text/html" charset="UTF-8" />' +

'</head>' + '<body>' +

'안녕하세요, ' + queryString.parse(postData).myName +

'(별명: ' + queryString.parse(postData).myNick + ')님!' +

'</body>' + '</html>';

res.writeHead(200, { 'Content-Type': 'text/html' });

res.write(sBody);

res.end();

}

exports.start = start;

exports.hello = hello;

      • 여러 button 사용예(formaction 이용)

= <form></form>을 여러 번 사용해도 동작함

<button type="submit" formaction="/hello">입력 완료</button>

<button type="submit" formaction="/start">입력 취소</button>

- Index.js

    • Ver 0.1

const myServer = require('./MyServer');

myServer.start();

    • Ver 0.2

const myServer = require('./MyServer');

const myRouter = require('./MyRouter');

myServer.start(myRouter.route);

    • Ver 0.3, 0.4, 0.5

const myServer = require('./MyServer');

const myRouter = require('./MyRouter');

const myHandlers = require('./MyHandlers');

let handle = {};

handle['/'] = myHandlers.start;

handle['/start'] = myHandlers.start;

handle['/hello'] = myHandlers.hello;

myServer.start(myRouter.route, handle);

[Node.js 함수]

- require() 함수

    • Module을 import(inlcude)하기 위한 함수

    • module.exports(혹은 exports)에 정의된 객체가 import됨

    • require 입력의 파일 이름에서 '.js'는 생략 가능

    • require 입력에 경로 표현 가능

[참고 문헌]

- Node.js: https://opentutorials.org/module/938

- 진짜기초 Node.js

- Build a simple Twitter Bot with Node.js in just 38 lines of code