์๋ฒ์ ํด๋ผ์ด์ธํธ์ ๊ด๊ณ
http ์์ฒญ์ ์๋ตํ๋ ๋ ธ๋ ์๋ฒ
๐ปcreateServer.js
const http = require('http');
http.createServer((req, res) => {
// ์ฌ๊ธฐ์ ์ด๋ป๊ฒ ์๋ตํ ์ง ์ ์ด์ค๋๋ค.
});
listen(ํฌํธ) ๋ฉ์๋๋ก ํน์ ํฌํธ์ ์ฐ๊ฒฐ
๐ปserver1.js
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }) //html์ string์ผ๋ก ์ธ์ํ๋ ๊ฒฝ์ฐ์ ์ฝ๋ ์ถ๊ฐ, ํ๊ธ ์ธ์ํ๊ธฐ ์ํด ์ฝ๋ ์ถ๊ฐ;
res.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Server!</p>');
})
.listen(8080, () => { // ์๋ฒ ์ฐ๊ฒฐ
console.log('8080๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ฉด 8080 ํฌํธ์ ์ฐ๊ฒฐ๋จ
localhost:8080 ๋๋ http://127.0.0.1:8080์ ์ ์
localhost๋ ์ปดํจํฐ ๋ด๋ถ ์ฃผ์
ํฌํธ๋ ์๋ฒ ๋ด์์ ํ๋ก์ธ์ค๋ฅผ ๊ตฌ๋ถํ๋ ๋ฒํธ
listening๊ณผ error ์ด๋ฒคํธ๋ฅผ ๋ถ์ผ ์ ์์.
๐ปserver1-1.js
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Server!</p>');
});
server.listen(8080);
server.on('listening', () => {
console.log('8080๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
server.on('error', (error) => {
console.error(error);
});
createServer๋ฅผ ์ฌ๋ฌ ๋ฒ ํธ์ถํ๋ฉด ๋จ.
๐ปserver1-2.js
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Server!</p>');
})
.listen(8080, () => { // ์๋ฒ ์ฐ๊ฒฐ
console.log('8080๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Server!</p>');
})
.listen(8080, () => { // ์๋ฒ ์ฐ๊ฒฐ
console.log('8081๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
write์ end์ ๋ฌธ์์ด์ ๋ฃ๋ ๊ฒ์ ๋นํจ์จ์
๐ปserver2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
//ํ๊ธ ๋์ค๊ฒ ํ๋ ค๋ฉด utf-8์ ์ ์ด์ค.
<title>Node.js ์น ์๋ฒ</title>
</head>
<body>
<h1>Node.js ์น ์๋ฒ</h1>
<p>๋ง๋ค ์ค๋น๋์
จ๋์?</p>
</body>
</html>
๐ปserver2.js
const http = require('http');
const fs = require('fs').promises;
http.createServer(async (req, res) => {
try {
const data = await fs.readFile('./server2.html');
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(data);
} catch (err) {
//try & catch๋ก ์๋ฌ ์ฒ๋ฆฌ
console.error(err);
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });//plain์ ์ผ๋ฐ ๋ฌธ์์ด์์ ์๋ ค์ค
res.end(err.message);
}
})
.listen(8081, () => {
console.log('8081๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
์๋ฒ์ ์์ฒญ์ ๋ณด๋ผ ๋๋ ์ฃผ์๋ฅผ ํตํด ์์ฒญ์ ๋ด์ฉ์ ํํ
/index.html์ด๋ฉด index.html์ ๋ณด๋ด๋ฌ๋ผ๋ ๋ป
ํญ์ html์ ์๊ตฌํ ํ์๋ ์์
์๋ฒ๊ฐ ์ดํดํ๊ธฐ ์ฌ์ด ์ฃผ์๊ฐ ์ข์
REST API(Representational State Transfer)
์๋ฒ์ ์์์ ์ ์ํ๊ณ ์์์ ๋ํ ์ฃผ์๋ฅผ ์ง์ ํ๋ ๋ฐฉ๋ฒ
/user์ด๋ฉด ์ฌ์ฉ์ ์ ๋ณด์ ๊ดํ ์ ๋ณด๋ฅผ ์์ฒญํ๋ ๊ฒ
/post๋ฉด ๊ฒ์๊ธ์ ๊ด๋ จ๋ ์์์ ์์ฒญํ๋ ๊ฒ
HTTP ์์ฒญ ๋ฉ์๋
GET: ์๋ฒ ์์์ ๊ฐ์ ธ์ค๋ ค๊ณ ํ ๋ ์ฌ์ฉ
POST: ์๋ฒ์ ์์์ ์๋ก ๋ฑ๋กํ๊ณ ์ ํ ๋ ์ฌ์ฉ(๋๋ ๋ญ ์จ์ผํ ์ง ์ ๋งคํ ๋)
PUT: ์๋ฒ์ ์์์ ์์ฒญ์ ๋ค์ด์๋ ์์์ผ๋ก ์นํํ๊ณ ์ํ ๋ ์ฌ์ฉ
PATCH: ์๋ฒ ์์์ ์ผ๋ถ๋ง ์์ ํ๊ณ ์ ํ ๋ ์ฌ์ฉ
DELETE: ์๋ฒ์ ์์์ ์ญ์ ํ๊ณ ์ํ ๋ ์ฌ์ฉ
ํด๋ผ์ด์ธํธ๊ฐ ๋๊ตฌ๋ ์๋ฒ์ HTTP ํ๋กํ ์ฝ๋ก ์ํต ๊ฐ๋ฅ
GitHub ์ ์ฅ์(https://github.com/zerocho/nodejsbook) ch4 ์์ค ์ฐธ์กฐ
๐ปresFront.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<title>RESTful SERVER</title>
<link rel="stylesheet" href="./restFront.css" />
</head>
<body>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<div>
<form id="form">
<input type="text" id="username">
<button type="submit">๋ฑ๋ก</button>
</form>
</div>
<div id="list"></div>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="./restFront.js"></script>
</body>
</html>
๐ปresFront.css
a { color: blue; text-decoration: none; }
๐ปabout.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>RESTful SERVER</title>
<link rel="stylesheet" href="./restFront.css" />
</head>
<body>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<div>
<h2>์๊ฐ ํ์ด์ง์
๋๋ค.</h2>
<p>์ฌ์ฉ์ ์ด๋ฆ์ ๋ฑ๋กํ์ธ์!</p>
</div>
</body>
</html>
๐ปresFront.js
async function getUser() { // ๋ก๋ฉ ์ ์ฌ์ฉ์ ๊ฐ์ ธ์ค๋ ํจ์
try {
const res = await axios.get('/users');
const users = res.data;
const list = document.getElementById('list');
list.innerHTML = '';
// ์ฌ์ฉ์๋ง๋ค ๋ฐ๋ณต์ ์ผ๋ก ํ๋ฉด ํ์ ๋ฐ ์ด๋ฒคํธ ์ฐ๊ฒฐ
Object.keys(users).map(function (key) {
const userDiv = document.createElement('div');
const span = document.createElement('span');
span.textContent = users[key];
const edit = document.createElement('button');
edit.textContent = '์์ ';
edit.addEventListener('click', async () => { // ์์ ๋ฒํผ ํด๋ฆญ
const name = prompt('๋ฐ๊ฟ ์ด๋ฆ์ ์
๋ ฅํ์ธ์');
if (!name) {
return alert('์ด๋ฆ์ ๋ฐ๋์ ์
๋ ฅํ์
์ผ ํฉ๋๋ค');
}
try {
await axios.put('/user/' + key, { name });
getUser();
} catch (err) {
console.error(err);
}
});
const remove = document.createElement('button');
remove.textContent = '์ญ์ ';
remove.addEventListener('click', async () => { // ์ญ์ ๋ฒํผ ํด๋ฆญ
try {
await axios.delete('/user/' + key);
getUser();
} catch (err) {
console.error(err);
}
});
userDiv.appendChild(span);
userDiv.appendChild(edit);
userDiv.appendChild(remove);
list.appendChild(userDiv);
console.log(res.data);
});
} catch (err) {
console.error(err);
}
}
window.onload = getUser; // ํ๋ฉด ๋ก๋ฉ ์ getUser ํธ์ถ
// ํผ ์ ์ถ(submit) ์ ์คํ
document.getElementById('form').addEventListener('submit', async (e) => {
e.preventDefault();
const name = e.target.username.value;
if (!name) {
return alert('์ด๋ฆ์ ์
๋ ฅํ์ธ์');
}
try {
await axios.post('/user', { name });
getUser();
} catch (err) {
console.error(err);
}
e.target.username.value = '';
});
๐ปrestServer.js์ ์ฃผ๋ชฉ
const http = require('http');
const fs = require('fs').promises;
const users = {}; // ๋ฐ์ดํฐ ์ ์ฅ์ฉ
http.createServer(async (req, res) => {
try {
if (req.method === 'GET')//์ฃผ์์ฐฝ์ ์น๋ ๊ฒ-> GET์์ฒญ {
if (req.url === '/') {
const data = await fs.readFile('./restFront.html');
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end(data);
} else if (req.url === '/about') {
const data = await fs.readFile('./about.html');
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end(data);
} else if (req.url === '/users') {
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
return res.end(JSON.stringify(users));
}
// /๋ /about๋ /users๋ ์๋๋ฉด
try {
const data = await fs.readFile(`.${req.url}`);
return res.end(data);
} catch (err) {
// ์ฃผ์์ ํด๋นํ๋ ๋ผ์ฐํธ๋ฅผ ๋ชป ์ฐพ์๋ค๋ 404 Not Found error ๋ฐ์
}
} else if (req.method === 'POST') {
if (req.url === '/user') {
let body = '';
// ์์ฒญ์ body๋ฅผ stream ํ์์ผ๋ก ๋ฐ์
req.on('data', (data) => {
body += data;
});
// ์์ฒญ์ body๋ฅผ ๋ค ๋ฐ์ ํ ์คํ๋จ
return req.on('end', () => {
console.log('POST ๋ณธ๋ฌธ(Body):', body);
const { name } = JSON.parse(body);
const id = Date.now();
users[id] = name;
res.writeHead(201, { 'Content-Type': 'text/plain; charset=utf-8' });
//201-์์ฑ๋จ
res.end('ok');
});
}
} else if (req.method === 'PUT') {
if (req.url.startsWith('/user/')) {
const key = req.url.split('/')[2];
let body = '';
req.on('data', (data) => {
body += data;
});
return req.on('end', () => {
console.log('PUT ๋ณธ๋ฌธ(Body):', body);
users[key] = JSON.parse(body).name;
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
return res.end('ok');
});
}
} else if (req.method === 'DELETE') {
if (req.url.startsWith('/user/')) {
const key = req.url.split('/')[2];
delete users[key];
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
return res.end('ok');
}
}
res.writeHead(404);
return res.end('NOT FOUND');
} catch (err) {
console.error(err);
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(err.message);
}
})
.listen(8082, () => {
console.log('8082๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค');
});
GET ๋ฉ์๋์์ /, /about ์์ฒญ ์ฃผ์๋ ํ์ด์ง๋ฅผ ์์ฒญํ๋ ๊ฒ์ด๋ฏ๋ก HTML ํ์ผ์ ์ฝ์ด์ ์ ์ก.
AJAX ์์ฒญ์ ์ฒ๋ฆฌํ๋ /users์์๋ users ๋ฐ์ดํฐ๋ฅผ ์ ์ก.
JSON ํ์์ผ๋ก ๋ณด๋ด๊ธฐ ์ํด JSON.stringify๋ฅผ ํด์ค.
๊ทธ ์ธ์ GET ์์ฒญ์ CSS๋ JS ํ์ผ์ ์์ฒญํ๋ ๊ฒ์ด๋ฏ๋ก ์ฐพ์์ ๋ณด๋ด์ฃผ๊ณ , ์๋ค๋ฉด 404 NOT FOUND ์๋ฌ๋ฅผ ์๋ต.
POST์ PUT ๋ฉ์๋๋ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ผ๋ฏ๋ก ํน๋ณํ ์ฒ๋ฆฌ๊ฐ ํ์. req.on('data', ์ฝ๋ฐฑ)๊ณผ req.on('end', ์ฝ๋ฐฑ) ๋ถ๋ถ์ธ๋ฐ์. 3.6.2์ ์ ๋ฒํผ์ ์คํธ๋ฆผ์์ ๋ฐฐ์ ๋ readStream์
๋๋ค. readStream์ผ๋ก ์์ฒญ๊ณผ ๊ฐ์ด ๋ค์ด์ค๋ ์์ฒญ ๋ณธ๋ฌธ์ ๋ฐ์ ์ ์์.
๋จ, ๋ฌธ์์ด์ด๋ฏ๋ก JSON์ผ๋ก ๋ง๋๋ JSON.parse ๊ณผ์ ์ด ํ ๋ฒ ํ์.
DELETE ๋ฉ์๋๋ก ์์ฒญ์ด ์ค๋ฉด ์ฃผ์์ ๋ค์ด ์๋ ํค์ ํด๋นํ๋ ์ฌ์ฉ์๋ฅผ ์ ๊ฑฐ.
ํด๋นํ๋ ์ฃผ์๊ฐ ์์ ๊ฒฝ์ฐ 404 NOT FOUND ์๋ฌ๋ฅผ ์๋ต.
. REST ์๋ฒ ์คํํ๊ธฐ
localhost:8085์ ์ ์
๊ฐ๋ฐ์๋๊ตฌ(F12) Network ํญ์์ ์์ฒญ ๋ด์ฉ ์ค์๊ฐ ํ์ธ ๊ฐ๋ฅ
์์ฒญ์๋ ํ ๊ฐ์ง ๋จ์ ์ด ์์
์ฟ ํค ๋ฃ๋ ๊ฒ์ ์ง์ ๊ตฌํ
์ฟ ํค: ํค=๊ฐ์ ์
const http = require('http');
http.createServer((req, res) => {
console.log(req.url, req.headers.cookie);
res.writeHead(200, { 'Set-Cookie': 'mycookie=test' });
res.end('Hello Cookie');
})
.listen(8083, () => {
console.log('8083๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
req.headers.cookie: ์ฟ ํค๊ฐ ๋ฌธ์์ด๋ก ๋ด๊ฒจ์์
req.url: ์์ฒญ ์ฃผ์
localhost:8082์ ์ ์
http ์์ฒญ๊ณผ ์๋ต์ ํค๋์ ๋ณธ๋ฌธ์ ๊ฐ์ง
writeHead ๋ฉ์๋์ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ๋ฃ์ ๊ฐ
์์ฒญ์ด ์ฑ๊ณตํ๋์ง ์คํจํ๋์ง๋ฅผ ์๋ ค์ค
2XX: ์ฑ๊ณต์ ์๋ฆฌ๋ ์ํ ์ฝ๋์ ๋๋ค. ๋ํ์ ์ผ๋ก 200(์ฑ๊ณต), 201(์์ฑ๋จ)์ด ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
3XX: ๋ฆฌ๋ค์ด๋ ์ (๋ค๋ฅธ ํ์ด์ง๋ก ์ด๋)์ ์๋ฆฌ๋ ์ํ ์ฝ๋์ ๋๋ค. ์ด๋ค ์ฃผ์๋ฅผ ์ ๋ ฅํ๋๋ฐ ๋ค๋ฅธ ์ฃผ์์ ํ์ด์ง๋ก ๋์ด๊ฐ ๋ ์ด ์ฝ๋๊ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๋ํ์ ์ผ๋ก 301(์๊ตฌ ์ด๋), 302(์์ ์ด๋)๊ฐ ์์ต๋๋ค.
4XX: ์์ฒญ ์ค๋ฅ๋ฅผ ๋ํ๋ ๋๋ค. ์์ฒญ ์์ฒด์ ์ค๋ฅ๊ฐ ์์ ๋ ํ์๋ฉ๋๋ค. ๋ํ์ ์ผ๋ก 401(๊ถํ ์์), 403(๊ธ์ง๋จ), 404(์ฐพ์ ์ ์์)๊ฐ ์์ต๋๋ค.
5XX: ์๋ฒ ์ค๋ฅ๋ฅผ ๋ํ๋ ๋๋ค. ์์ฒญ์ ์ ๋๋ก ์์ง๋ง ์๋ฒ์ ์ค๋ฅ๊ฐ ์๊ฒผ์ ๋ ๋ฐ์ํฉ๋๋ค. ์ด ์ค๋ฅ๊ฐ ๋จ์ง ์๊ฒ ์ฃผ์ํด์ ํ๋ก๊ทธ๋๋ฐํด์ผ ํฉ๋๋ค. ์ด ์ค๋ฅ๋ฅผ ํด๋ผ์ด์ธํธ๋ก res.writeHead๋ก ์ง์ ๋ณด๋ด๋ ๊ฒฝ์ฐ๋ ์๊ณ , ์๊ธฐ์น ๋ชปํ ์๋ฌ ๋ฐ์ ์ ์๋ฒ๊ฐ ์์์ 5XX๋ ์ฝ๋๋ฅผ ๋ณด๋ ๋๋ค. 500(๋ด๋ถ ์๋ฒ ์ค๋ฅ), 502(๋ถ๋ ๊ฒ์ดํธ์จ์ด), 503(์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์์)์ด ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
์ฟ ํค์ ๋ด ์ ๋ณด๋ฅผ ์ ๋ ฅ
๐ปcookie2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>์ฟ ํค&์ธ์
์ดํดํ๊ธฐ</title>
</head>
<body>
<form action="/login">
<input id="name" name="name" placeholder="์ด๋ฆ์ ์
๋ ฅํ์ธ์" />
<button id="login">๋ก๊ทธ์ธ</button>
</form>
</body>
</html>
๐ปcookie2.js
const http = require('http');
const fs = require('fs').promises;
const url = require('url');
const qs = require('querystring');
const parseCookies = (cookie = '') =>
cookie
.split(';')
.map(v => v.split('='))
.reduce((acc, [k, v]) => {
acc[k.trim()] = decodeURIComponent(v);
return acc;
}, {});
http.createServer(async (req, res) => {
const cookies = parseCookies(req.headers.cookie); // { mycookie: 'test' }
// ์ฃผ์๊ฐ /login์ผ๋ก ์์ํ๋ ๊ฒฝ์ฐ
if (req.url.startsWith('/login')) {
const { query } = url.parse(req.url);
const { name } = qs.parse(query);
const expires = new Date();
// ์ฟ ํค ์ ํจ ์๊ฐ์ ํ์ฌ์๊ฐ + 5๋ถ์ผ๋ก ์ค์
expires.setMinutes(expires.getMinutes() + 5);
res.writeHead(302, {//302๋ redirection
Location: '/',
'Set-Cookie': `name=${encodeURIComponent(name)//ํ๊ธ์ด๊ธฐ ๋๋ฌธ์
}; Expires=${expires.toGMTString()//์ฟ ํค๋ง๋ฃ ๊ธฐ๊ฐ(์ง์ ์ ์ ์ ์์)
}; HttpOnly; Path=/`,
});
res.end();
// name์ด๋ผ๋ ์ฟ ํค๊ฐ ์๋ ๊ฒฝ์ฐ
} else if (cookies.name) {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(`${cookies.name}๋ ์๋
ํ์ธ์`);
} else {
try {
const data = await fs.readFile('./cookie2.html');
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(data);
} catch (err) {
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(err.message);
}
}
})
.listen(8084, () => {
console.log('8084๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
Set-Cookie ์ ๋ค์ํ ์ต์ ์ด ์์
localhost:8084 ํฌํธ์ ์ ์
์ฟ ํค์ ์ ๋ณด๋ ๋ ธ์ถ๋๊ณ ์์ ๋๋ ์ํ์ด ์์
const http = require('http');
const fs = require('fs').promises;
const url = require('url');
const qs = require('querystring');
const parseCookies = (cookie = '') =>
cookie
.split(';')
.map(v => v.split('='))
.reduce((acc, [k, v]) => {
acc[k.trim()] = decodeURIComponent(v);
return acc;
}, {});
const session = {};
http.createServer(async (req, res) => {
const cookies = parseCookies(req.headers.cookie);
if (req.url.startsWith('/login')) {
const { query } = url.parse(req.url);
const { name } = qs.parse(query);
const expires = new Date();
expires.setMinutes(expires.getMinutes() + 5);
const uniqueInt = Date.now();
session[uniqueInt] = {
name,
expires,
};
res.writeHead(302, {
Location: '/',
'Set-Cookie': `session=${uniqueInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
});
res.end();
// ์ธ์
์ฟ ํค๊ฐ ์กด์ฌํ๊ณ , ๋ง๋ฃ ๊ธฐ๊ฐ์ด ์ง๋์ง ์์๋ค๋ฉด
} else if (cookies.session && session[cookies.session].expires > new Date()) {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(`${session[cookies.session].name}๋ ์๋
ํ์ธ์`);
} else {
try {
const data = await fs.readFile('./cookie2.html');
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(data);
} catch (err) {
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(err.message);
}
}
})
.listen(8085, () => {
console.log('8085๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
localhost:8085
์ค ์๋ฒ์์๋ ์ธ์
์ ์ง์ ๊ตฌํํ์ง ๋ง๊ธฐ X
6์ฅ์์ ๋์ค๋ express-session ์ฌ์ฉํ๊ธฐ
์น ์๋ฒ์ SSL ์ํธํ๋ฅผ ์ถ๊ฐํ๋ ๋ชจ๋
http ์๋ฒ๋ฅผ https ์๋ฒ๋ก
๐ปserver1.js
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Server!</p>');
})
.listen(8080, () => { // ์๋ฒ ์ฐ๊ฒฐ
console.log('8080๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
๐ปserver1-3.js
const https = require('https');
const fs = require('fs');
https.createServer({
cert: fs.readFileSync('๋๋ฉ์ธ ์ธ์ฆ์ ๊ฒฝ๋ก'),
key: fs.readFileSync('๋๋ฉ์ธ ๋น๋ฐํค ๊ฒฝ๋ก'),
ca: [
fs.readFileSync('์์ ์ธ์ฆ์ ๊ฒฝ๋ก'),
fs.readFileSync('์์ ์ธ์ฆ์ ๊ฒฝ๋ก'),
],
//์ธ์ฆ๊ธฐ๊ด์์ ๊ฐ์ ธ์์ผํจ
}, (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Server!</p>');
})
.listen(443, () => {
console.log('443๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
SSL ์ํธํ์ ๋๋ถ์ด ์ต์ HTTP ํ๋กํ ์ฝ์ธ http/2๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋
https ๋ชจ๋์ http2๋ก, createServer ๋ฉ์๋๋ฅผ createSecureServer ๋ฉ์๋๋ก
๐ปserver1-4.js
const http2 = require('http2');
const fs = require('fs');
http2.createSecureServer({
cert: fs.readFileSync('๋๋ฉ์ธ ์ธ์ฆ์ ๊ฒฝ๋ก'),
key: fs.readFileSync('๋๋ฉ์ธ ๋น๋ฐํค ๊ฒฝ๋ก'),
ca: [
fs.readFileSync('์์ ์ธ์ฆ์ ๊ฒฝ๋ก'),
fs.readFileSync('์์ ์ธ์ฆ์ ๊ฒฝ๋ก'),
],
}, (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Server!</p>');
})
.listen(443, () => {
console.log('443๋ฒ ํฌํธ์์ ์๋ฒ ๋๊ธฐ ์ค์
๋๋ค!');
});
๊ฒฐ๊ณผ
๊ธฐ๋ณธ์ ์ผ๋ก ์ฑ๊ธ ์ค๋ ๋์ธ ๋ ธ๋๊ฐ CPU ์ฝ์ด๋ฅผ ๋ชจ๋ ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๋ชจ๋
๋ง์คํฐ ํ๋ก์ธ์ค์ ์์ปค ํ๋ก์ธ์ค
๐ปcluster.js
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`๋ง์คํฐ ํ๋ก์ธ์ค ์์ด๋: ${process.pid}`);
// CPU ๊ฐ์๋งํผ ์์ปค๋ฅผ ์์ฐ
for (let i = 0; i < numCPUs; i += 1) {
cluster.fork();
}
// ์์ปค๊ฐ ์ข
๋ฃ๋์์ ๋
cluster.on('exit', (worker, code, signal) => {
console.log(`${worker.process.pid}๋ฒ ์์ปค๊ฐ ์ข
๋ฃ๋์์ต๋๋ค.`);
console.log('code', code, 'signal', signal);
cluster.fork();
});
} else {
// ์์ปค๋ค์ด ํฌํธ์์ ๋๊ธฐ
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Cluster!</p>');
setTimeout(() => { // ์์ปค ์กด์ฌ๋ฅผ ํ์ธํ๊ธฐ ์ํด 1์ด๋ง๋ค ๊ฐ์ ์ข
๋ฃ
process.exit(1);
}, 1000);
}).listen(8086);
console.log(`${process.pid}๋ฒ ์์ปค ์คํ`);
}
์์ฒญ์ด ๋ค์ด์ฌ ๋๋ง๋ค ์๋ฒ ์ข ๋ฃ๋๋๋ก ์ค์
์์ปค๊ฐ ์ฃฝ์ ๋๋ง๋ค ์๋ก์ด ์์ปค๋ฅผ ์์ฑ