4.1 요청과 응답 이해하기
클라이언트에서 서버로 요청을 보내고 서버는 요청의 내용을 읽고 처리한 뒤 클라이언트에 응답을 보낸다.
따라서 서버에는 요청을 받는 부분과 응답을 보내는 부분이 있어야 한다.
const http = require('http');
http.createServer((req, res) => {
// 여기에 어떻게 응답할지 적어줍니다
});
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, () => { // 서버 연결
console.log('8080번 포트에서 서버 대기 중입니다!');
});
writeHead는 응답에 대한 정보를 기록하는 메서드이다.
첫 번재 인수로 200 상태 코드를 두 번째 인수로 응답에 대한 정보를 보내는데 콘텐츠 형식이 HTML임을 알리고 있다.
이 정보가 기록되는 부분을 헤더라고 한다.
write의 첫 번째 인수는 클라이언트로 보낼 데이터이다. 지금은 HTML 문장을 보냈지만 버퍼를 보낼 수 도 있다.
데이터가 기록되는 부분을 본문이라고 한다.
end는 응답을 종료하는 메서드이다. 만약 인수가 있다면 그 데이터도 클라이언트로 보내고 응답을 종료한다.
[localhost]
localhost는 현재 컴퓨터의 내부 주소를 가리키며 외부에서는 접근할 수 없고 자신의 컴퓨터에서만 접근할 수 있다.
localhost 대신 127.0.0.1을 주소로 사용해도 같다. 이러한 숫자 주소를 IP라고 한다.
[port]
포트는 서버 내에 프로세스를 구분하는 번호이다.
포트 번호는 IP 주소 뒤에 콜론과 함께 붙여 사용한다.
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) {
console.error(err);
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end(err.message);
}
})
.listen(8081, () => {
console.log('8081번 포트에서 서버 대기 중입니다!');
});
요청이 들어오면 FS 모듈로 HTML 파일을 읽는다.
data 변수에 저장된 버퍼를 그대도 클라이언트에 보낸다.
요청 과정 중 에러가 발생했다고 해서 응답을 보내지 않으면 안된다.
응답을 보내지 않으면 클라이언트는 서버로부터 응답이 오길 기다리다가 일정 시간이 지난 후 Timeout 처리된다.
[상태코드]
2XX: 성공을 알리는 상태 코드이다. 대표적으로 200(성공), 201(작성됨)이 많이 사용된다.
3XX: 리다이렉션(다른 페이지로 이동)을 알리는 상태 코드이다. 어떤 주소를 입력했는데 다른 주소의 페이지로 넘어갈 때 이 코드가 사용된다. 대표적으로 301(영구 이동), 302(임시 이동), 304(수정되지 않음)는 요청의 응답으로 캐시를 사용했다는 뜻이다.
4XX: 요청 오류를 나타낸다. 대표적으로 400(잘못된 요청), 401(권한 없음), 403(금지됨), 404(찾을 수 없음)가 있다.
5XX: 서버 오류를 나타낸다. 500(내부 서버 오류), 502(불량 게이트웨이), 503(서비스를 사용할 수 없음)가 있다.
4.2 요청과 응답 이해하기
REST는 REpresentational State Transfer의 줄임말로, 서버의 자원을 정의하고 자원에 대한 주소를 지정하는 방법을 가리킨다.
단순한 명사만 있으면 무슨 동작을 행하라는 것인지 알기 어려움으로 REST에서는 주소 외에도 HTTP 요청 메서드라는 것을 사용한다.
[HTTP 요청 메서드]
- GET: 서버에 자원을 새로 등록하고자 할 때 사용한다. 요청의 본문에 새로 등록할 데이터를 넣어 보낸다.
- POST: 서버의 자원을 요청에 들어 잇는 자원으로 치환하고자할 때 사용한다. 요청의 본문에 치환할 데이터를 넣어 보낸다.
- PATCH: 서버 자원의 일부만 수정하고자 할 때 사용한다. 요청 본문에 일부 수정할 데이터를 넣어 보낸다.
- DELETE: 서버의 자원을 삭제하고자 할 때 사용한다. 요청의 본문에 데이터를 넣지 않는다.
- OPTIONS: 요청을 하기 전에 통신 옵션을 설명하기 위해 사용한다.
코드를 작성하기 전 아래 표처럼 대략적인 주소를 먼저 설계하는 것이 좋다.
HTTP 메서드 | 주소 | 역할 |
GET | / | restFront.html 파일 제공 |
GET | /about | about.html 파일 제공 |
GET | /users | 사용자 목록 제공 |
POST | /user | 사용자 등록 |
4.3 쿠키와 세션 이해하기
[cookie]
쿠키는 유효기간이 있으며 name=zerocho와 같이 '키-값'의 쌍이다.
쿠키 간에는 세미콜론을 넣어 각각을 구분한다.
서버로부터 쿠키가 오면, 웹브라우저는 쿠키를 저장해뒀다가 다음 요청할 때마다 쿠키를 동봉해서 보낸다.
즉, 서버는 미리 클라이언트에 요청자를 추정할 만한 정보를 쿠키로 만들어서 보내고 클라이언트로부터 쿠키를 받아 요청자를 파악한다.
쿠키는 요청의 헤더에 담겨 전송된다.
브라우저는 응답의 헤더에 따라 쿠키를 저장한다.
- 쿠키명=쿠키값: 기본적인 쿠키의 값이다.
- Expires=날짜: 만료 기한이다. 이 기한이 지나면 쿠키가 제거된다.
- Max-age=초: 날짜 대신 초를 입력할 수 있다. Expires보다 우선한다.
- Domain=도메인명: 쿠키가 전송될 도메인을 특정할 수 있다.
- Path=URL: 쿠키가 전송될 URL을 특정할 수 있다.
- Secure: HTTPS일 경우에만 쿠키가 전송된다.
- HttpOnly: 설정 시 자바스크립트에서 쿠키에 접근할 수 없다.
[session]
사용자가 웹 브라우저를 통해 웹서버에 접속한 시점으로부터 웹 브라우저를 종료하여 연결을 끝내는 시점까지 같은 사용자로부터 오는 일련의 요청을 하나의 상태로 보고, 그 상태를 일정하게 유지하는 기술.즉 방문자가 웹 서버에 접속해있는 상태를 하나의 단위로 보고 그것을 세션이라고 한다.
웹 서버에 웹 컨테이너의 상태를 유지하기 위한 정보를 저장
브라우저를 닫거나, 서버에서 세션을 삭제했을 때 삭제되므로 쿠키보다 보안이 좋다.
4.4 https와 http2
https 모듈은 웹 서버에 SSL 암호화를 추가하여 다른 사람이 요청을 가로채더라도 내용을 확인할 수 없게 한다.
하지만 https는 암호화를 적용하는 만큼 인증해줄 기관이 필요하여 인증서를 구입해야 한다.
(Let's Encrypt 같은 기관에서 무료로 발급도 해준다.)
[http2]
http2 모듈은 SSL 암호화와 더불어 최신 HTTP 프로토콜인 http/2를 사용할 수 있게 한다.
http/2는 요청 및 응답 방식이 기존 http/1.1보다 개선되어 훨씬 효율적으로 요청을 보낸다.
http/2는 웹의 속도도 많이 개선된다
.
4.5 cluster
[cluster]
nodejs는 하나의 프로세스가 메모리 제한이 있어 이 제한을 늘리는 것보다 Worker 개수를 늘려 병렬 처리하는 것이 효율 측면에서 높고 권장하고 있다. 이 Worker를 늘리기 위해서 cluster라는 기술을 사용한다.
기본적으로 싱글 프로세스가 동작하는 노드가 CPU 코어를 모두 사용할 수 있게 해주는 모듈이다.
포트를 공유하는 노드 프로세스를 여러 개 둘 수도 있어 요청이 분산되어 서버에 무리가 덜 가게 된다.
클러스터에는 마스터 프로세스와 워커 프로세스가 있다.
마스터 프로세스에 요청이 들어오면 마스터 프로세스는 워커 프로세스에 요청을 분배한다.
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>');
}).listen(8086);
console.log(`${process.pid}번 워커 실행`);
}
'Programming > NodeJS' 카테고리의 다른 글
Node.js 교과서 [Express, Middleware, Route, 템플릿 엔진] #6 (1) | 2024.02.11 |
---|---|
Node.js 교과서 [npm] #5 (0) | 2024.02.10 |
Node.js 교과서 [이벤트, 예외 처리] #3.4 (0) | 2024.02.04 |
Node.js 교과서 [파일 시스템] #3.3 (0) | 2024.02.04 |
Node.js 교과서 [노드 내장 모듈] #3.2 (0) | 2024.02.04 |