Node.js(2)
http 모듈
http.createServer
- 서버의 응답내용을 지정해준다.
- 매개변수로 request, response를 가지고 있는데 request를 줄여 req라 표현하고, response를 줄여 res라 표현해준다.
createServer.js
const http = require('http');
http.createServer((req, res) => {
// 여기에 어떻게 응답할지 적어줍니다
});
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번 포트에서 서버 대기 중입니다!');
});
listen 메서드
.listen(포트번호, () => {
함수이름
});
- 위에서 res.write로 출력하는(응답하는) 동작이 성공적으로 실행되었을 때 서버 연결을 해주는 메서드
- 클라이언트에 공개할 포트 번호와 포트 연결 완료 후 실행될 콜백 함수를 넣는다.
- http.createServer().listen(포트 이름, 실행할 함수)
- 8080 포트에서 요청이 오길 기다리게 됨
res.writeHead
res.writeHead(성공적인 요청/실패한 요청 등등의요청번호, { 'Content-Type': 'text/html; charset=utf-8'//요청에대한 정보 즉 헤더 });
- 응답에 대한 정보를 기록하는 메서드
res.write
- 서버에서 클라이언트로 응답을 보낼 때 body에 데이터를 담아서 보냄
res.write('클라이언트로 보낼 데이터');
res.end
- 서버의 응답을 종류하는 메서드
res.end('클라이언트로 보낼 데이터');
통신 과정
server1-1.js
const http = require('http');
const server = http.createServer((req, res) => {
//server = http.createServer(()) =>{}) 로, 변수에 응답을 담는다.
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) => { //에러 메세지와 에러 출력시의 case
console.error(error);
});
서버를 여러개 띄어보기
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(8081, () => { // 서버 연결
console.log('8081번 포트에서 서버 대기 중입니다!');
});
fs 모듈
- res.write와 res.end에 일일이 HTML을 적는 것은 비효율적이므로 미리 HTML 파일을 만들어놓고, fs가 데이터를 읽어드린다.
server2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="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; //fs 모듈을 사용하는데, async-await 비동기적 함수를 동기적으로 사용할 수 있게 해준다.
http.createServer(async (req, res) => {
try {
const data = await fs.readFile('./server2.html'); // 요청이 들어오면 fs 모듈로 HTML 파일을 읽어 data 변수에 저장한다.
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(data); //실행이 정상적으로 될 때 ,res.end나 res.write에 실행하고자 하느 데이터를 담는다.
} catch (err) { //실행이 정상적으로 되지 않을 때
console.error(err);
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(err.message); // 예기치 못한 에러가 발생한 경우에는 에러 메시지를 응답
}
})
.listen(8081, () => {
console.log('8081번 포트에서 서버 대기 중입니다!');
});
라우팅
- 요청별로 다른 응답을 할 수 있도록 하는 것
- css나 js 또는 이미지 같은 파일을 요청할 수도 있고 특정 동작을 행하는 것을 요청할 수 있다는 것을 명심해야함 (.html 형식만 요청하는게 절대 아님)
REST API(API 문서에 넣어서 정의해야 한다.)
- 서버의 자원을 정의하고 자원에 대한 주소를 지정하는 방법
- REAST API 요청 메서드
• GET: 서버 자원을 가져오고자 할 때 사용하며, 요청의 본문(body)에 데이터를 넣지 않고, url에 넣어서 보낸다. 데이터를 서버로 보내야 한다면 쿼리스트링을 사용한다.
• POST: 서버에 자원을 새로 등록하고자 할 때 사용한다. 요청의 본문에 새로 등록할 데이터를 넣어 보낸다.
• PUT: 서버의 자원을 요청에 들어 있는 자원으로 치환하고자 할 때 사용하고 요청의 본문에 치환할 데이터를 넣어 보낸다.
• PATCH: 서버 자원의 일부만 수정하고자 할 때 요청의 본문에 일부 수정할 데이터를 넣어 보낸다.
• DELETE: 서버의 자원을 삭제하고자 할 때 사용하며 요청의 본문에 데이터를 넣지 않음
• OPTIONS: 요청을 하기 전에 통신 옵션을 설명하기 위해 사용한다.
REST API 문서 정의
쿠키
- 키 - 값 쌍
- 서버로부터 쿠키가 오면 웹 브라우저는 쿠키를 저장해두었다가 다음에 요처할 때마다 쿠키를 동봉해서 보내고 서버는다음 요청에 들어 있는 쿠키를 읽어서 사용자가 누구인지 파악함
- 쿠키는 요청의 헤더(Cookie)에 담겨 전송되고 브라우저는 응답의 헤더(Set-Cookie)에 따라 쿠키를 저장한다.
쿠키를 직접 생성하고 요청자의 브라우저에 넣어보기
cookie.js
const http = require('http');
http.createServer((req, res) => {
// req.url은 주소의 path와 search 부분을 알린다.
console.log(req.url, req.headers.cookie); //req.header.cookie : req 객체에 담겨 있는 쿠키를 가져 가져온다.
res.writeHead(200, { 'Set-Cookie': 'mycookie=test' });
res.end('Hello Cookie');
})
.listen(8083, () => {
console.log('8083번 포트에서 서버 대기 중입니다!');
});
콘솔
쿠키값 설정하기
- 쿠키명=쿠키값: 기본적인 쿠키의 값입니다. mycookie=test 또는 name=zerocho와 같이 설정함
- Expires=날짜: 만료 기한입니다. 이 기한이 지나면 쿠키가 제거된다. 기본값은 클라이언트가 종료될 때까지임
- Max-age=초: Expires와 비슷하지만 날짜 대신 초를 입력할 수 있으며 해당 초가 지나면 쿠기가 제거된다. Expires보다 우선적으로 시행된다.
• Domain=도메인명: 쿠키가 전송될 도메인을 특정할 수 있습니다. 기본값은 현재 도메인입니다.
• Path=URL: 쿠키가 전송될 URL을 특정할 수 있습니다. 기본값은 ‘/’이고, 이 경우 모든 URL에서 쿠키를 전송할 수 있습니다.
• Secure: HTTPS일 경우에만 쿠키가 전송됩니다.
• HttpOnly: 설정 시 자바스크립트에서 쿠키에 접근할 수 없습니다. 쿠키 조작을 방지하기 위해 설정하는 것이 좋습니다.
세션
https
- http + SSL 암호화
https.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번 포트에서 서버 대기 중입니다!');
});
- http.createServer이 인자 두 개를 받는다.
- 두 번째 인수는 앞에서 본 서버 로직이고, 첫 번째 인수는 인증서에 관련된 옵션 객체이다.
- 인증서 확장자 : perm ,cert, key, ca
- fs.readFileSync : 인증서를 읽어오는 메서드
http2 모듈 - http 통신 방식을 훨씬 간편하고 효율적으로 바꿔준 통신 방식으로 노드 모듈 안에 포함되어 있다.
http2.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번 포트에서 서버 대기 중입니다!');
});
- https 모듈을 http2로, createServer 메서드를 createSecure Server 메서드로 바꾸면 된다.
cluster - 싱글 프로세스로 동작하는 노드가 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);
});
} 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}번 워커 실행`);