node.js 첫걸음
TRANSCRIPT
“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 환경에서발생하는요소고려에대한부담감소
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의완료를대기하지않고, 다른작업을처리할수있음• 위의이유로많은요청을수용가능하다
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
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');
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');
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.
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/
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/
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)• 데이터베이스에대한권한제어.
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
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
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) {// ...
});