const http = require('http');
http.createServer((req, res) => { // 응답 처리 }
서버 연결(한번에 여러 개 연결하기)
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, () => { // 클라이언트에 공개할 포트번호, 포트 연결 후 실행되는 콜백함수
// 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(8081, () => { // 8081번 서버 연결 console.log('8081번 포트에서 서버 대기 중입니다!'); });
실행결과
* 참고로 포트 연결은 안전하게 1024 이후의 숫자로 연결하는 것이 좋음(포트 충돌 방지)
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>');
});
server.listen(8080);
server.on('listening', () => {
// listening 이벤트 리스너
console.log('8080번 포트에서 서버 대기 중입니다!') });
server.on('error', (error) => {
// error 리스너
console.error(error);
});
서버 HTML 파일을 따로 만들어 연결하기
const http = require('http');
const fs = require('fs').promises;
http.createServer(async (req, res) =>{
try { // 요청이 들어오면 fs모듈로 HTML파일을 읽음
const data = await fs.readFile(렌더링할 html 파일);
res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
res.end(data); // 읽은 HTML 파일을 보냄
} catch(err) {
console.error(err); // text/plain은 일반 문자열을 의미
res.writeHead(500, {'Content-Type': 'text/plain; charset=utf-8'});
res.end(err.message); }
}).listen(8081, () => {
console.log('8081번 포트에서 서버 대기 중입니다!'
);
});
위처럼 오류가 났을 때 예외처리는 응답에 에러코드를 담아 보내는 것이다.
오류가 났다고 응답을 보내지 않으면 서버는 응답이 오기를 기다리다가 Timeout(시간 초과) 처리한다.
서버에 요청을 보낼 때 그것이 어떠한 요청인지는 주소에 있다.
(/index.html 은 index.html 파일을 가져오라는 뜻이다. 그 외에도 css, js를 불러오는 것도 가능하다.)
서버가 이해하기 쉬운 주소를 표현하는 방법 -> REST
REST (Representational State Transfer)
const http = request('http');
const fs = require('fs').pormises;
http.createServer(async (req,res) => {
try {
console.log(req.method, req.url); // GET 요청이 들어왔을 때
if (req.method === 'GET') {
if (req.url === '/') {
//자바스크립트는 await 키워드를 만나면 프라미스가 처리(settled)될 때까지 기다림
const data = await fs.readFile(로드할 HTML 파일);
res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
return res.end(data);
} // 주소가 / 이 아니면
try {
const data = await fs.readFile(`.${req.url}`);
return res.end(data);
} catch(err) {
// 주소에 해당하는 라우트를 못 찾았다는 404 에러 발생
} else if (req.method === 'POST') {
// POST /user 사용자를 새로 저장
if (req.url === '/user') {
let body = ''; // 요청의 body를 stream 형식으로 받음
// req.on() -> 요청의 본문에 들어 있는 데이터를 꺼내기 위한 작업
req.on('data', (data) => { body += data; }); // 요청의 body를 다 받은 후 실행됨
// req.on() -> 요청의 본문에 들어 있는 데이터를 꺼내기 위한 작업
return req.on('end', () => { console.log('POST 본문(Body):', body);
const { name } = JSON.parse(body);
const id = Date.now();
user[id] = name;
res.writeHead(201);
res.end('등록 성공');
});
}
} else if (req.method === 'PUT') {
// PUT 요청이 들어왔을 때
if (req.url.startsWith('/user/')) {
const key = req.url.split('/')[2];
delete users[key];
return res.end(JSON.stringify(users));
}
}
res.writeHead(404);
return res.end('NOT FOUND');
} catch(err) {
console.error(err);
res.writeHead(500, {'Content-Type': 'text/plain; carset=utf-8' });
res.end(err.message); }
})
.listen(8080, () => {
console.log('8082번 포트 서버 대기중');
});
const http = require('http');
http.createServer((req, res) => {
//req.headers.cookie -> req 객체의 쿠키
console.log(req.url, req.headers.cookie);
res.writeHead(200, {
//res의 헤더에 쿠키 기록
// 쿠키의 형태는 문자열, 아래와 같은 형태로 쿠키 지정
'Set-Cookie': 'mycookie=test'
}); res.end('Hello Cookie');
}) .listen(8083, () => {
console.log('8083번 포트 대기중');
})
결과
가장 처음에는 req.headers.cookie에 아무 값도 들어가 있지 않다가 한번 response가 돌아온 이후에는 쿠키가 test로 설정된 것을 알 수 있다.
favicon이란 웹 사이트 상단의 아이콘을 말한다. 이 아이콘 정보를 불러오기 위해 요청을 보내는 것이다.
로그인하고 5분간 유지하기
<!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>
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); // 주소가 /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, { Location: '/', // 'Set-Cookie': `session=${uniqueInt}; Expires= ${expires.toGMTString()}; HttpOnly; Path=/`, 'Set-Cookie': `name=${encodeURIComponent(name)}; Expires= ${expires.toGMTString()}; HttpOnly; Path=/`, }); res.end(); // cookies.session && session[cookies.session].expires > new Date() } else if(cookies.name) { // name이라는 쿠키가 있는 경우 res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'}); // res.end(`${session[cookies.session].name}); res.end(`${cookies.name}님 반가워요`); } else { // 처음 방문했을 때는 로그인하는 페이지로 이동 try { const data = await fs.readFile('./4장/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 옵션
쿠키가 그대로 노출되어 있는 것을 방지하기 위해 '세션'을 사용한다. 그러면 값에 쿠키 대신 세션 아이디가 들어가게 되고 쿠키 대신 세션 아이디를 주고받으면서 본인을 확인한다. 이렇게 세션을 위해 사용하는 쿠키를 '세션 쿠키'라고 한다.
const https = require('https');
const fs = require('fs');
https.createServer({
cert: fs.readFielSync('도메인 인증서 경로'),
key: fs.readFileSync('도메인 비밀키 경로'),
ca: [ fs.readFileSync('상위 인증서 경로'),
fs.readFileSync('상위 인증서 경로'), ], },
(req, res) => {
res.writeHead(200, {'Content-Type': 'text/html; carset=utf-8'});
res.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Server!</p>');
}) .listen(443, () => { console.log('443번 포트 대기중'); });
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>');
}).listen(8086); console.log(`${process.pid}번 워커 실행`); }
결과
코어 개수에 맞게 워커 프로세스가 실행된 것을 확인할 수 있다.
워커가 실행된 개수만큼 서버에 오류가 나서 종료되더라도 서버가 정상작동할 수 있다. cluster를 통해 서버가 완전히 다운되는 걸 방지할 수 있으나, 오류를 고치는 것이 우선적으로 진행되어야 한다. 워커가 다운되면 다시 새로운 워커를 생성하도록 하여 무한으로 서버가 종료되는 걸 방지할 수도 있다.
[Node.js] 6장 익스프레스 웹 서버 만들기 (0) | 2021.11.15 |
---|---|
[Node.js] 5장 패키지 매니저 (0) | 2021.11.08 |
[Node.js] 3장 기능 알아보기(2) (0) | 2021.10.30 |
[Node.js] 3장 노드 기능 알아보기 (0) | 2021.10.11 |
[Node.js] 2장 알아두어야 할 자바스크립트 (0) | 2021.10.04 |