node.js 첫걸음

80
Node.js 첫걸음 처음부터 시작하는 Node.js SeungHyun Lee [email protected]

Upload: seunghyun-lee

Post on 14-Apr-2017

217 views

Category:

Software


1 download

TRANSCRIPT

Node.js 첫걸음처음부터시작하는 Node.js

SeungHyun Lee

[email protected]

Node.js?

“Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.”“As an asynchronous event driven JavaScript runtime, Node is designed to build scalable network applications.”

- nodejs.org

• 크롬의 V8 자바스크립트엔진을기반으로만들어진자바스크립트런타임

• 네트워크어플리케이션제작을위한비동기이벤트기반방식의자바스크립트런타임

What is Node.js?

“Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.”“As an asynchronous event driven JavaScript runtime, Node is designed to build scalable network applications.”

- nodejs.org

• 크롬의 V8 자바스크립트엔진을기반으로만들어진자바스크립트런타임

• 네트워크어플리케이션제작을위한비동기이벤트기반방식의자바스크립트런타임

= 서버사이드자바스크립트프레임워크

What is Node.js?

Feature

• Open Source• Asynchronous & Event-driven• Non-blocking I/O• Single threaded• Chrome’s V8 Engine

Open Source

“Permission is hereby granted, free of charge … without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software …”

- LICENSE of node.js

• 수정, 배포등을포함한일체의권리에제한을받지않고사용할수있는오픈소스

• https://github.com/nodejs/node

Asynchronous & Event-driven

• 절차지향프로그래밍 : 진입점에서부터모든동작이차례대로수행

• 이벤트드리븐 : 입력혹은출력(event)이발생함에따라동작이처리(driven)

• 절차지향프로그래밍방식은동기적(Synchronous)으로동작이처리되는반면, 이벤트드리븐방식은비동기적(Asynchronous)으로동작이처리됨

• 가장기본적인처리방식으로콜백(callback)이존재

Non-blocking I/O

• Blocking : 어떠한작업이완료될때까지다른처리를막는(blocking) 방식

• Non-blocking : 처리할작업을맡겨두고(non-blocking), 결과를따로처리하는방식

• Sync/Asnyc의개념과혼동될수있으나, Blocking/Non-blocking을처리하는방식으로 Sync/Async를이용하게된다.

Single threaded

• Tomcat, Apache : 사용자의요청에대해 thread를생성해처리

• Node.js : 단일 thread의 event loop 상에서요청을처리

• Context switching에대한비용감소

• Multi-thread 환경에서발생하는요소고려에대한부담감소

Single threaded event loop

Chrome’s V8 Engine

• JIT(Just-In-Time) compile• Efficient garbage collection• Inline cache• Hidden classes

Chrome’s V8 Engine

• JIT(Just-In-Time) compile• Efficient garbage collection• Inline cache• Hidden classes

>> 빠르며고성능의 JavaScript 엔진

Why Node.js?

• Fast• Single Thread 기반의비동기 I/O 처리• CPU가특정 I/O의완료를대기하지않고, 다른작업을처리할수있음• 위의이유로많은요청을수용가능하다

Hello World!> console.log(“Hello world!”)

Installation (Windows)

• Download on https://nodejs.org/en/download/• ‘Windows Installer’

• ‘Next’ 혹은 ‘Install’, ‘Finish’만선택해주면설치완료

Installation (Linux)

• Download on https://nodejs.org/en/download/• ‘Source Code’

• GNU make를위한의존성패키지설치

• configure.sh를통한 make 설정

• Make• Install

Installation (Linux)

wget https://nodejs.org/dist/v4.4.3/node-v4.4.3.tar.gz sudo apt-get update && apt-get upgrade sudo apt-get install build-essential libssl-dev tar -xzf node-v4.4.3.tar.gz cd node-v4.4.3 ./configure make sudo make install

Hello World

vim helloword.js // helloworld.js

console.log(“hello world!”)

node helloworld.js // execute

Hello World

vim helloword.js // helloworld.js

console.log(“hello world!”)

node helloworld.js // execute

Simple Server

vim simple_server.js // simple_server.js

var http = require('http')

http.createServer( (request, response) => {response.writeHead(200, {'Content-Type': 'text/html'});response.end('<h1>Hello world!</h1>');

}).listen(3000)

console.log('Server running at http://localhost:3000');

node simple_server.js // execute (http://localhost:3000)

Simple Server

HTTP Serverrequire(‘http’)

Simple Server

var http = require('http')

http.createServer( (request, response) => {response.writeHead(200, {'Content-Type': 'text/html'});response.end('<h1>Hello world!</h1>');

}).listen(3000)

console.log('Server running at http://localhost:3000');

Simple Server

var http = require('http')

http.createServer( (request, response) => {response.writeHead(200, {'Content-Type': 'text/html'});response.end('<h1>Hello world!</h1>');

}).listen(3000)

console.log('Server running at http://localhost:3000');

Simple Server

var http = require('http')

http.createServer( (request, response) => {response.writeHead(200, {'Content-Type': 'text/html'});response.end('<h1>Hello world!</h1>');

}).listen(3000)

console.log('Server running at http://localhost:3000');

=> HTTP Module

HTTP Module

• HTTP 웹서버와관련된기능을담고있는모듈

• HTTP Module은다음과같은클래스를포함• 요청(Request)와응답(Response)를처리할수있는 Server• 클라이언트의요청에대한정보를담는 IncomingMessage• 서버의처리결과에대한정보를담는 ServerResponse• 다른서버와의통신기능을수행할수있는 ClientRequest

참고 : https://nodejs.org/api/http.html

• TCP/IP 기반으로웹상에서정보를주고받을수있는프로토콜

• 클라이언트와서버사이에이루어지는요청/응답(request/response) 프로토콜

• OSI 7 Layer 중 Application Layer에해당

• HTML 페이지를전달하는데주로사용

HTTP

참고 : RFC 2616 (https://tools.ietf.org/html/rfc2616)

HTTP Communication

출처 : http://www.slideshare.net/origamiaddict/http-40249449

TCP Connection(Transport layer)

HTTP Connection(Application layer)

HTTP Message Structure

• HTTP 메시지는크게 Request와 Response로나뉘어짐

• 각메시지는 Header와 Body로구성

• Header는커넥션및쿠키, 파일종류등통신에필요한각종정보를서술

• Body는실제본문으로서전송할데이터를서술

• 메시지전문은아래와같이구성

Request-Line | Status-Line*(message-header CRLF)CRLF[ message-body ]

참고 : https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

HTTP Message Structure

HTTP/1.1 200 OKServer: GitHub.comDate: Wed, 29 Jun 2016 06:16:00 GMTContent-Type: text/html; charset=utf-8Transfer-Encoding: chunkedStatus: 200 OKCache-Control: no-cacheX-UA-Compatible: IE=Edge,chrome=1X-Runtime: 0.019390

<!DOCTYPE html><html lang="en" class=" is-copy-enabled is-u2f-enabled"><head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article:

http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#"><meta charset='utf-8'><link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/frameworks-

fef7fdfe41dd435c6d82f93b486dc62bc095ebd12cd24fa2a817c8bb45dc073e.css" integrity="sha256-/vf9/kHdQ1xtgvk7SG3GK8CV69Es0k+iqBfIu0XcBz4=" media="all" rel="stylesheet" />…

Message Headers

Message Body

참고 : https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

Simple Server

var http = require('http')

http.createServer( (request, response) => {response.writeHead(200, {'Content-Type': 'text/html'});response.end('<h1>Hello world!</h1>');

}).listen(3000)

console.log('Server running at http://localhost:3000');

Simple Server

var http = require('http')

http.createServer( (request, response) => {response.writeHead(200, {'Content-Type': 'text/html'}); // Message Header 작성response.end('<h1>Hello world!</h1>'); // Message Body 작성

}).listen(3000)

console.log('Server running at http://localhost:3000');

HTTP server

var http = require('http') // ‘http’ 모듈 로드

var server = http.createServer( (request, response) => { // server 객체 생성response.writeHead(200, {'Content-Type': 'text/html'});response.end('<h1>Hello world!</h1>');

}).on('request', function() { // ‘request’ 이벤트에 콜백 매핑console.log('Request On');

}).on('connection', function() { // ‘connection’ 이벤트에 콜백 매핑console.log('Connection On');

}).on('close', function() { // ‘close’ 이벤트에 콜백 매핑console.log('Close On');

}).listen(3000); // 서버 실행

console.log('Server running at http://localhost:3000');

HTTP server

Serving static files

var http = require('http')var fs = require('fs') // ‘fs’ 모듈 로드

var server = http.createServer( (request, response) => {fs.readFile('index.html', function(error, data) { // 파일 읽기

response.writeHead(200, {'Content-Type': 'text/html'}); // Header 작성response.end(data); // 파일 전송

});}).listen(3000);

console.log('Server running at http://localhost:3000');

Serving static files

var http = require('http')

// text/html 형식의 파일을 전송 할 것이라 명시response.writeHead(200, {‘Content-Type’: ‘text/html’});

console.log('Server running at http://localhost:3000');

Serving static files

Page Renderingrequire(‘ejs’) / require(‘jade’)

Web Page Presentation

• 사용자의요청에따라 HTML 페이지를보여주기위해서는?

var http = require('http')

var server = http.createServer( request, response => {response.writeHead(200, {'Content-Type': 'text/html'});response.end(‘<html>

<head><title>Hello world!</title></head><body><h1>Welcome to Node.js</h1><p>example page…</p></body></html>’);

}).listen(3000);

• 웹페이지소스를하드코딩으로작성 == 번거롭다

Web Page Presentation

• 사용자의요청에따라 HTML 페이지를보여주기위해서는?

var http = require('http')

var server = http.createServer( request, response => {response.writeHead(200, {'Content-Type': 'text/html'});response.end(‘<html>

<head><title>Hello world!</title></head><body><h1>Welcome to Node.js</h1><p>example page…</p></body></html>’);

}).listen(3000);

• 웹페이지소스를하드코딩으로작성 == 번거롭다

Web Page Presentation

• 사용자의요청에따라 HTML 페이지를보여주기위해서는?

var http = require('http')

var server = http.createServer( request, response => {response.writeHead(200, {'Content-Type': 'text/html'});response.end(‘<html>

<head><title>Hello world!</title></head><body><h1>Welcome to Node.js</h1><p>example page…</p></body></html>’);

}).listen(3000);

• 웹페이지소스를하드코딩으로작성 == 번거롭다

Web Page Presentation

• 사용자의요청에따라 HTML 페이지를보여주기위해서는?

var http = require('http')

var server = http.createServer( request, response => {response.writeHead(200, {'Content-Type': 'text/html'});response.end(‘<html>

<head><title>Hello world!</title></head><body><h1>Welcome to Node.js</h1><p>example page…</p></body></html>’);

}).listen(3000);

• 웹페이지소스를하드코딩으로작성 == 번거롭다

Web Page Presentation

• 사용자의요청에따라 HTML 페이지를보여주기위해서는?

var http = require('http')

var server = http.createServer( request, response => {response.writeHead(200, {'Content-Type': 'text/html'});response.end(‘<html>

<head><title>Hello world!</title></head><body><h1>Welcome to Node.js</h1><p>example page…</p></body></html>’);

}).listen(3000);

• 웹페이지소스를하드코딩으로작성 == 번거롭다

Page Rendering

• Business Logic과 Presentation Logic을구분하는것이기본개념

• View를 EJS 문법(EJS) 및 HAML(Pug)에따라제작

• 만들어진 View는 Template Engine을통해렌더링

• Template Engine에는 Pug(Jade), EJS, Dust, Mustache 등이존재

참고 : http://paularmstrong.github.io/node-templates

참고 :https://github.com/pugjs/pug

https://github.com/pugjs/pug/issues/2184

• HAML(HTML Abstract Markup Language)의영향을받은 Template Engine• 본명칭은 Jade로이쪽이더많이알려져있으나, 네이밍이슈로최근개명됨

• 들여쓰기를통해계층구조를표현

• 들여쓰기가잘못될시전혀다른결과혹은오류를발생

Pug (Jade)

Syntax

HTML

<!DOCTYPE html><html lang="en">

<head><title>Pug</title><script type="text/javascript">

if (foo) bar(1 + 5)</script>

</head><body>

<h1>Pug - node template engine</h1><div id="container" class="col">

<p>You are amazing</p><p>Pug is a terse and simple

templating language with a strong focus on performance and powerful features.</p>

</div></body>

</html>

참고 : http://jade-lang.com

Pug

doctype htmlhtml(lang="en")head

title= pageTitlescript(type='text/javascript').

if (foo) bar(1 + 5)body

h1 Pug - node template engine#container.col

if youAreUsingPugp You are amazing

elsep Get on it!

p.Pug is a terse and simple templatinglanguage with a strong focus on performance and powerful features.

Install Pug package

• Pug는외부모듈이므로실행전 NPM을이용해설치를진행

npm install pug

If Jade…?

npm install jade

Simple Pug

var http = require('http');var pug = require('pug');var fs = require('fs');

http.createServer(function (request, response) {fs.readFile('index.pug', 'utf8', function (error, data) {

var fn = pug.compile(data);response.writeHead(200, {'Content-Type': 'text/html'});response.end(fn());

});}).listen(3000);

console.log('Server running at http://localhost:3000');

참고 : http://jade-lang.com/api/

Simple Pug

var http = require('http');var pug = require('pug'); // ‘pug’ 모듈 로드var fs = require('fs');

http.createServer(function (request, response) {fs.readFile('index.pug', 'utf8', function (error, data) {

var fn = pug.compile(data); // HTML 코드 제너레이터 생성response.writeHead(200, {'Content-Type': 'text/html'});response.end(fn()); // 제너레이터를 이용해 응답

});}).listen(3000);

console.log('Server running at http://localhost:3000');

참고 : http://jade-lang.com/api/

Simple Pug

var http = require('http');var pug = require('pug'); // ‘pug’ 모듈 로드var fs = require('fs');

http.createServer(function (request, response) {response.writeHead(200, {'Content-Type': 'text/html'});response.end(pug.renderFile('index.pug')); // 파일명을 이용한 코드 생성

}).listen(3000);

console.log('Server running at http://localhost:3000');

참고 : http://jade-lang.com/api/

Simple Pug

Passing Parameters

var http = require('http');var pug = require('pug');var fs = require('fs');

http.createServer(function (request, response) {fs.readFile('index.pug', 'utf8', function (error, data) {

var fn = pug.compile(data);var params = { pageTitle: 'Hello, Pug', youAreUsingPug: true }; // 넘겨줄 변수 목록response.writeHead(200, { 'Content-Type‘ : 'text/html‘ });response.end(fn(params)); // 함께 컴파일

});}).listen(3000);

console.log('Server running at http://localhost:3000');

참고 : http://jade-lang.com/api/

Passing Parameters

Database

Necessity of Database

• 특정사람들만글을읽고쓸수있는게시판제작

• 각사람들에게계정을주고권한을부여

• 로그인한사용자들만글을쓰고읽기가가능

Q : 사용자정보를저장해둘곳?

Necessity of Database

• 특정사람들만글을읽고쓸수있는게시판제작

• 각사람들에게계정을주고권한을부여

• 로그인한사용자들만글을쓰고읽기가가능

Q : 사용자정보를저장해둘곳?

A : Database

Database?

• 데이터중복의최소화

• 데이터의무결성

• DBMS (DataBase Management System)• 복수사용자관리

• 다수의사용자에의해접근 = 동일한데이터의동시사용또는변경• 데이터의일관성보장필요• 허용된권한을통해서만데이터로접근가능

• 복수의연결및자원관리

Language of Database

• SQL• DB와의사소통을하기위한표준언어• DB 및데이터의읽기, 쓰기(생성), 수정, 삭제, 관리등의기능을수행

• DDL (Data Definition Language) • 데이터베이스의구조정의또는변경.

• DML (Data Manupulation Language)• 데이터의삽입, 삭제, 검색, 수정.

• DCL (Data Control Language)• 데이터베이스에대한권한제어.

MySQL on Node.jsrequire(mysql)

Basic Usage

var mysql = require('mysql');var connection = mysql.createConnection({host : 'localhost',user : 'me',password : 'secret',database : 'my_db'

});

connection.connect();

connection.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {if (err) throw err;

console.log('The solution is: ', rows[0].solution);});

connection.end();

Connect

Query

Disconnect

Basic Usage

Expressrequire(‘express’)

Express

“Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.”

- expressjs.com

• Express : Node.js를기반으로한가볍고유연한Web Application Framework

• Main features• Routing• Managing middlewares• Serving static files

참고 : Express (http://expressjs.com)

Express & Connect

• ‘Connect’는미들웨어(Middleware)를기반으로 Node.js의 HTTP 서버기능을확장해주는모듈 (extensible HTTP server framework for node using "plugins" known as middleware)

• 초기 ‘Express’는 Connect를기반으로설계

• 이로인해여러문제가발생 (Connect에대한의존성, 성능이슈등)• 위의문제를해결하기위해 Express 4.0 버전부터의존성을제거하고독자적인

Router를가지게됨

참고 : Express GitHub (https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x)

Routing?

• 클라이언트가요청한각각의경로(URL)에대한처리는어떻게할까• http://localhost:3000/• http://localhost:3000/hello• http://localhost:3000/world• ….

Routing?

• 클라이언트가요청한각각의경로(URL)에대한처리는어떻게할까• http://localhost:3000/• http://localhost:3000/hello• http://localhost:3000/world• ….

=> 마지막컴포넌트(/, /hello, /world)를구하고, 각각에대한로직을구성

Routing on Node.js

var http = require('http');var url = require('url');

http.createServer( function (req, res) {var pathname = url.parse(request.url).pathname;if(pathname == '/') {

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

} else if(pathname == '/hello') {response.writeHead(200, { 'Content-Type': 'text/html' });response.end('routing: /hello');

} else if(pathname == '/world') {response.writeHead(200, { 'Content-Type': 'text/html' });response.end('routing: /world');

} }).listen(3000);

Routing on Node.js

var http = require('http');var url = require('url');

http.createServer( function (req, res) {var pathname = url.parse(request.url).pathname;if(pathname == '/') {

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

} else if(pathname == '/hello') {response.writeHead(200, { 'Content-Type': 'text/html' });response.end('routing: /hello');

} else if(pathname == '/world') {response.writeHead(200, { 'Content-Type': 'text/html' });response.end('routing: /world');

} }).listen(3000);

/

/hello

/world

Routing

• if-else / switch-case 문을이용한분기처리는분기가많아질수록비효율적

• 또한자칫스파게티코드가되기쉬움

• Routing 기능만을독립적으로수행하고, 로직을주입할수있도록하자

Routing

• if-else / switch-case 문을이용한분기처리는분기가많아질수록비효율적

• 또한자칫스파게티코드가되기쉬움

• Routing 기능만을독립적으로수행하고, 로직을주입할수있도록하자

=> Router (라우터)

Routing on Express

var express = require('express');var app = express();

app.get('/', function (req, res) {res.send('Hello World!');

}).post('/', function (req, res) {res.send('Got a POST request');

}).put('/user', function (req, res) {res.send('Got a PUT request at /user');

}).delete('/user', function (req, res) {res.send('Got a DELETE request at /user');

}).listen(3000, function () {console.log('Example app listening on port 3000!');

});

Routing on Express

var express = require('express'); // express 모듈 로드var app = express();

app.get('/', function (req, res) { // ‘/’의 GET 메서드에 대한 분기res.send('Hello World!');

}).post('/', function (req, res) { // ‘/’의 POS 메서드에 대한 분기res.send('Got a POST request');

}).put('/user', function (req, res) { // ‘/’의 PUT 메서드에 대한 분기res.send('Got a PUT request at /user');

}).delete('/user', function (req, res) { // ‘/’의 DELETE 메서드에 대한 분기res.send('Got a DELETE request at /user');

}).listen(3000, function () {console.log('Example app listening on port 3000!');

});

Page Rendering

// app.jsvar express = require('express');var app = express();

app.set('view engine', ‘jade');

app.get('/', function (req, res) {// View engine을 이용해 Page renderingres.render('index', { title: 'Hey', message: 'Hello there!'});

}).listen(3000, function () {console.log('Server running at http://localhost:3000');

});

// index.jadehtmlheadtitle!= title

bodyh1!= message

Page Rendering

// app.jsvar express = require('express');var app = express();

app.set('view engine', ‘jade'); // jade 엔진을 사용하도록 설정

app.get('/', function (req, res) {// View engine을 이용해 Page renderingres.render('index', { title: 'Hey', message: 'Hello there!'});

}).listen(3000, function () {console.log('Server running at http://localhost:3000');

});

// index.jadehtmlheadtitle!= title

bodyh1!= message

Page Rendering

Using Middleware

var express = require('express');var app = express();var cookieParser = require('cookie-parser');var bodyParser = require('body-parser');

app.use(cookieParser());app.use(bodyParser());app.use(function (req, res, next) {

console.log('Time:', Date.now());next();

});

app.get('/', function (req, res) {// ...

});

Using Middleware

var express = require('express');var app = express();var cookieParser = require('cookie-parser');var bodyParser = require('body-parser');

app.use(cookieParser()); // Connect의 Cookie Parser 모듈을 주입app.use(bodyParser()); // Connect의 Body Parser 모듈을 주입app.use(function (req, res, next) { // 사용자 정의 모듈을 주입

console.log('Time:', Date.now());next();

});

app.get('/', function (req, res) {// ...

});

Q & A

End.