node.js

[Node.js] #4 http 모듈로 서버 만들기(2)

로춘남 2021. 11. 12. 17:35
728x90


3. 쿠키와 세션 이해하기

클라이언트에서 보내는 요청의 단점 → 누가 요청을 보내는지 모름.

로그인 이후 새로고침 후에도 로그아웃이 되지 않는 이유는 클라이언트가 서버에 내가 누군지를 지속적으로 알려주고 있기때문.

내가 누구인지 기억하기 위해서 서버는 요청에 대한 응답을 할 때 쿠키라는것을 같이 보낸다. 쿠키는 유효 기간이 있으며 name=로춘남 과 같은 단순한 '키-값'의 쌍이다.

서버로부터 쿠키가 오면 웹 브라우저는 쿠키를 저장해두었다가 다음에 요청 할 때마다 쿠키를 동봉해서 보낸다. 서버는 요청에 들어있는 쿠키를 읽어서 사용자가 누구인지 파악을 하게 된다.

- 쿠키명-쿠키값 : 기본적인 쿠키의값

- Expires=날짜 : 만료 기한. 이 기한이 지나면 쿠키가 제거.

- Max-age=초 : Expires와 비슷하지만 날짜 대신 초를 입력 할 수 있음.

- Domain=도메인명 : 쿠기가 전송될 도메인을 특정

- Path=URL : 쿠키가 전송될 URL을 특정. 기본값은 '/'. 이 경우에는 모든 URL에서 쿠키전송 가능

- Secure : HTTPS일 경우에만 쿠키 전송

- HttpOnly : 설정 시 자바스크립트에서 쿠키에 접근 할 수 없음.

4. https와 http2

https 모듈은 웹  서버에 SSL암호화를 추가. GET이나 POST 요청을 할 때 오가는 데이터를 암호화해서 중간에 다른 사람이 요청을 가로채더라도 내용을 확인 할 수 없게함.

서버에 암호화를 적용하려면 https 모듈을 사용해야하지만, 이것은 아무나 사용 할 수가 없다. 암호화를 적용하는만큼 그것을 인증해줄 수 있는 기관이 필요해서 경우에 따라 인증서는 인증 기관에서 구입을 해야한다. 인증서를 받는 과정은 생각보다 복잡하고 도메인이 따로 필요하다.

 

만약 발급받은 인증서가 있다면,

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번 포트에서 서버 대기 중입니다!');
  });

이런식으로 처리를 해주면 된다. createServer 메소드가 인수 2개를 받는다는것을 알 수 있고, 두 번쨰 인수는 http 모듈과 같이 서버 로직. 첫 번째 인수는 인증서에 관련된 옵션객체이다. 인증서를 구입하면 pem이나 crt, 또는 key 확장자를 가진 파일들을 제공하며, 이 파일들을 fs.readFileSync 메서드로 읽어 cert, key, ca 옵션에 알맞게 넣어주면된다. 실제 서버에서는 80포트 대신 443 포트를 사용하고 있다.

노드의 http2 모듈은 SSL암호화와 더불어 최신 HTTP 프로토콜인 http/2를 사용 할 수 있게 해준다. http2는 기존 http/1.1 보다 요청 및 응답이 개선되며 훨씬 효율적으로 보내는것이 가능하며! 속도도 빠르다!

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번 포트에서 서버 대기 중입니다!');
  });

http2를 적용했을 경우 https 모듈과 비슷하다. https 모듈을  https2로, createServer 메서드를 createSecureServer 메서드로 바꿔주기만하면 된다!

HTTP/1.1과 HTTP/2의 비교

Icons made by DinosoftLabs from www.flaticon.com

5. cluster

cluster 모듈은 기본적으로 싱글 프로세스로 동작하는 노드가 CPU코어를 모두 사용할 수 있게 해주는 모듈. 포트를 공유하는 노드 프로세스를 여러개 둘 수 있으므로, 요청이 많이 들어왔을 때 병렬로 실행된 서버의 개수만큼 요청이 분산되게 할 수 있다. → 서버에 무리를 덜 가게 할 수 있음.

노드는 보통 코어를 1개만 사용하지만, cluster 모듈을 설정하여 코어 하나당 노드 프로세스 하나가 돌아가게 할 수도 있다. 성능이 1개일때보다 개선은 되지만 메모리를 공유하지 못한다는 단점과, 세션을 메모리에 저장하는 경우 문제가 될 수 있다. 이럴 경우에는 레디스 등의 서버를 도입하여 해결 할 수 있다.

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}번 워커 실행`);
}

※ 실무에서는 보통 pm2 등의 모듈로 cluster 기능을 사용함.


참조 : Node.js 교과서(개정2판)

728x90