node.js로 서버 만들기 - node.js 배우기
1. 서버란?
서버와 클라이언트
서버는 요청을 받는 응답자이고, 클라이언트는 요청을 보내는 요청자입니다.
- 클라이언트: 웹 브라우저(Chrome, Safari).
- 서버: 네이버, 구글 같은 웹사이트를 운영하는 컴퓨터.
쉽게 서버의 동작 이해하기
- 브라우저에서 "구글 검색"을 입력(요청)하면,
- 구글의 서버가 요청을 받아서 검색 결과를 준비(처리)한 뒤,
- 준비된 검색 결과를 브라우저로 보냄(응답).
서버의 예
웹 서버: 웹사이트를 보여주는 서버.
- 예: 네이버, 구글, 유튜브.
파일 서버: 파일을 저장하고 전송하는 서버.
- 예: Google Drive, Dropbox.
게임 서버: 온라인 게임에서 플레이어 간 연결을 관리하는 서버.
- 예: LOL, PUBG.
호스팅 서버: 웹사이트를 저장하고 관리하는 서버.
- 예: AWS, Azure.
2. 프로젝트 시작
- 프로젝트 생성
NPM 명령어 로 프로젝트를 생성합니다.
node-server프로젝트 폴더를 생성하고,npm init명령어로package.json파일을 생성합니다.
$ mkdir node-server
$ cd node-server
$ npm init -y
2. 서버 만들기
서버 만들기 전에 w3schools의 Node.js HTTP 모듈을 참고하세요.
- 간단한 HTTP 서버 만들기
HTTP 서버는 클라이언트(브라우저)의 요청을 받고, 이에 응답하는 프로그램입니다.
Node.js는 http 모듈을 사용해 쉽게 서버를 생성할 수 있습니다.
http.createServer()메서드로 서버를 생성합니다.server.listen()메서드로 서버를 실행합니다.
// server.js
// Node.js의 기본 내장 모듈인 'http' 모듈을 불러옵니다.
const http = require('http');
// http 서버를 생성하는 메서드
// 콜백 함수로 request(요청)과 response(응답) 객체를 매개변수로 받습니다.
const server = http.createServer((req, res) => {
// 요청이 들어오면 응답합니다.
res.writeHead(200, { 'Content-Type': 'text/html' }); // 응답 헤더 설정
res.write('<h1>Hello, Node.js!</h1>'); // 응답 본문
res.end('<p>http 모듈 공부 중...</p>'); // 응답 종료
});
// 서버가 8080 포트에서 실행되도록 설정합니다.
// .listen() : 특정 포트에서 서버를 실행하고 클라이언트의 요청을 기다립니다.
server.listen(8080, () => {
console.log('8080 포트에서 서버가 실행 중입니다.');
});
- localhost는 자신의 컴퓨터를 가리키는 주소입니다.
- 8080은 서버가 실행될 포트 번호입니다.
$ node server.js
8080 포트에서 서버가 실행 중입니다.
- http 상태 코드
HTTP 상태 코드는 클라이언트의 요청에 대한 서버의 응답 상태를 나타내는 코드입니다.
- 1xx: 처리중(Informational) / 요청을 받았으며 프로세스를 계속합니다.
- 2xx: 성공(Success) / 요청을 성공적으로 받았으며 이해했고 수용했습니다.
- 3xx: 리다이렉션(Redirection) / 요청을 완료하기 위해 추가 동작이 필요합니다.
- 4xx: 클라이언트 오류(Client Error) / 요청의 문법이 잘못되었거나 요청을 처리할 수 없습니다.
- 5xx: 서버 오류(Server Error) / 서버가 유효한 요청에 대해 충족을 실패했습니다.
참고: MDN HTTP 상태 코드
주요 상태 코드
- 200: OK / 요청이 성공했습니다.
- 404: Not Found / 요청한 페이지를 찾을 수 없습니다.
- 500: Internal Server Error / 서버에 오류가 발생했습니다.
- 리스닝 이벤트(이벤트 리스너)
Node.js에서 리스닝 이벤트는 특정 상황(이벤트)이 발생했을 때 실행되는 코드
서버가 클라이언트의 요청을 받아들이기 시작할 때 발생하는 이벤트입니다.
server.listen()메서드는 서버를 실행하고 클라이언트의 요청을 기다리는 메서드입니다.- 서버가 정상적으로 실행되면
listening이벤트가 발생합니다. server.on('listening', 콜백함수)로 리스닝 이벤트를 등록할 수 있습니다.server.on('error', 콜백함수)로 에러 이벤트를 등록할 수 있습니다.
// server.js
const http = require('http');
// 서버 생성
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write('<h1>Hello, Node.js!</h1>');
res.end('<p>http 모듈 공부 중...</p>');
});
// `listening` 이벤트 등록
server.on('listening', () => {
console.log('서버가 정상적으로 실행되었습니다!');
});
// `error` 이벤트 등록
server.on('error', (error) => {
console.error('서버 실행 중 오류 발생:', error.message);
});
// 서버 실행
server.listen(8080, () => {
console.log('8080 포트에서 서버가 실행 중입니다.');
});
$ node server.js
8080 포트에서 서버가 실행 중입니다.
서버가 정상적으로 실행되었습니다!
크롬의 주소창에 http://localhost:8080을 입력하면, "Hello, Node.js!"가 출력됩니다.
참고
터미널에서는 메시지가 보이지만, 크롬의 개발자 도구 콘솔창에서 메시지가 보이지 않는 이유는 터미널 출력(console.log)와 클라이언트(브라우저) 출력이 서로 다른 개념이기 때문입니다.
이유
서버 측 로그
- console.log는 Node.js 서버에서 실행되는 코드에서 발생한 로그를 출력하기 때문에
- 위 메시지는 서버의 터미널에서만 확인할 수 있습니다.
클라이언트(브라우저) 로그
- 브라우저의 개발자 도구 콘솔창은 서버에서 받은 HTML, JavaScript 등의 응답에서 발생한 로그를 보여주는 곳입니다.
- 현재 서버가 브라우저로 응답한 HTML에는 클라이언트 측 로그를 출력하는 코드가 없기 때문에 크롬 콘솔창에서 메시지가 보이지 않습니다.
참고
파일을 수정할 때마다 서버를 재시작하는 것이 번거롭다면, nodemon 패키지를 사용해보세요.
$ npm install -g nodemon
$ nodemon server.js
{
"scripts": {
"start": "nodemon server.js"
}
}
$ npm start
- 파일을 보내는 응답 코드
응답 콜백에 html을 직접 넣어주는 것이 아니라 파일을 따로 만들어 파일시스템(fs)을 이용해 읽어서 보내는 방법
fs파일을 읽어오는 모듈fs.promises.readFile()파일을 읽어오는 메서드res.end(data)로 파일을 응답 본문으로 보내면서 요청 종료
$ touch index.html
<!-- index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Node.js로 서버 만들기</title>
</head>
<body>
<h1>Node.js로 서버 만들기</h1>
<p>파일을 읽어와 응답하는 서버</p>
</body>
</html>
aync/await문법을 사용하면 비동기 처리를 동기 처리처럼 작성할 수 있습니다.try-catch문법을 사용하면 에러 처리를 쉽게 할 수 있습니다.
// fs-test.js
const http = require('http');
const fs = require('fs');
const server = http.createServer(async (req, res) => {
try {
// fs.promises.readFile() : 파일을 읽어오는 메서드
const data = await fs.promises.readFile('./index.html');
// 200이면 성공
res.writeHead(200, { 'Content-Type': 'text/html' });
// 파일을 읽어온 data를 응답 본문으로 보내면서 요청 종료
res.end(data);
} catch (error) {
console.error(error);
// 500이면 서버 오류
res.writeHead(500, { 'Content-Type': 'text/plain' });
// 에러 메시지를 응답 본문으로 보내면서 요청 종료
res.end(error.message);
}
});
// 8080 서버 실행
server.listen(8080, () => {
console.log('8080 포트에서 서버가 실행 중입니다.');
});
3. 요청 객체(req), 응답 객체(res)
Node.js의 HTTP 모듈을 사용하면 서버에서 요청 객체(req)와 응답 객체(res)를 사용할 수 있습니다.
- 요청 객체(req)
req.url: 클라이언트가 요청한 URL 주소req.method: 클라이언트가 요청한 HTTP 메서드req.headers: 클라이언트의 요청 헤더 정보
- 응답 객체(res)
res.writeHead(상태코드, 헤더객체): 응답 헤더 설정res.write(데이터): 응답 본문 작성res.end(데이터): 응답 종료
- REST를 통한 페이지 라우팅
REST(Representational State Transfer)는 자원을 이름(자원의 표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모델입니다.
req.url로 요청한 URL 주소를 확인하고, 해당 URL에 따라 다른 응답을 보내는 방식if문을 사용해 URL에 따라 다른 응답을 보내는 방식을 라우팅이라고 합니다.- 이렇게 URL에 따라 다른 응답을 보내는 것을 RESTful API라고 합니다.
<!-- index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Node.js로 서버 만들기</title>
</head>
<body>
<h1>Main</h1>
</body>
</html>
<!-- about.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>About : Node.js로 서버 만들기</title>
</head>
<body>
<h1>About</h1>
</body>
</html>
// rest.js
const http = require('http');
const fs = require('fs');
const server = http.createServer(async (req, res) => {
try {
if (req.url === '/') {
const data = await fs.promises.readFile('./index.html');
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(data);
} else if (req.url === '/about') {
const data = await fs.promises.readFile('./about.html');
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(data);
} else {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('<h1>404 Not Found</h1>');
}
} catch (error) {
console.error(error);
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(error.message);
}
});
server.listen(8080, () => {
console.log('8080 포트에서 서버가 실행 중입니다.');
});
서버를 실행하고, 크롬의 주소창에 http://localhost:8080, http://localhost:8080/about를 입력해보세요.
크롬 브라우저에서 개발자 도구를 열고 Network 탭을 확인하면, 요청과 응답 상태 코드를 확인할 수 있습니다.
4. 쿼리스트링(Query String)
쿼리스트링(Query String)은 URL 주소에 데이터를 포함하여 서버로 전달하는 방식입니다.
req.url로 요청한 URL 주소를 확인하고, URL에 포함된 쿼리스트링을 분석하는 방식- URL에
?를 사용해 쿼리스트링을 추가하고,&로 여러 개의 쿼리스트링을 구분합니다. url.parse()메서드로 URL을 분석하고,querystring모듈로 쿼리스트링을 분석합니다.
- 기본 구조
http://localhost:8080/?name=Node.js&age=20
?: 쿼리스트링의 시작name=Node.js: name이 Node.js인 쿼리스트링&: 쿼리스트링 구분자size=230: size가 230인 쿼리스트링
- url.parse() 메서드
url.parse()메서드로 URL을 분석하면, URL의 여러 정보를 객체로 반환합니다.url.parse(주소): URL을 분석하여 URL 객체를 반환합니다.url.parse(주소, true): URL을 분석하여 URL 객체와 쿼리스트링 객체를 반환합니다.
// 이런 URL이 있다면
'http://localhost:8080/search?category=shoes&color=black&size=260'
// url.parse()로 분석하면 이렇게 분리됩니다
{
protocol: 'http:',
host: 'localhost:8080',
pathname: '/search',
query: 'category=shoes&color=black&size=260'
}
- querystring 모듈
querystring모듈은 URL의 쿼리스트링을 객체로 변환하거나, 객체를 쿼리스트링으로 변환하는 모듈입니다.querystring.parse(쿼리스트링): 쿼리스트링을 객체로 변환합니다.querystring.stringify(객체): 객체를 쿼리스트링으로 변환합니다.
const querystring = require('querystring');
const parsedQuery = querystring.parse(parsedUrl.query);
// 이제 parsedQuery는 객체 형태가 됩니다
{
category: 'shoes',
color: 'black',
size: '260'
}
- 실제 사용 예시
1) URL 주소에 쿼리스트링 추가
https://shop.com/?category=shoes&color=black&size=260
이는 다음을 의미합니다.
- 카테고리 : 신발
- 색상 : 검정
- 사이즈 : 260
// querystring.js
const http = require('http');
const url = require('url');
// querystring 모듈을 불러옵니다.
const querystring = require('querystring');
const server = http.createServer((req, res) => {
// URL 문자열을 URL 객체로 변환
const parsedUrl = url.parse(req.url);
// URL 객체에서 쿼리스트링을 객체로 변환
const query = querystring.parse(parsedUrl.query);
// 상품 검색 처리
if (query.category || query.color || query.size) {
// 검색 조건 메시지 생성
let searchMessage = '<h2>검색 조건:</h2>';
if (query.category) searchMessage += `<p>카테고리: ${query.category}</p>`;
if (query.color) searchMessage += `<p>색상: ${query.color}</p>`;
if (query.size) searchMessage += `<p>사이즈: ${query.size}</p>`;
// 검색 결과 메시지 (실제로는 데이터베이스 조회 결과가 들어갈 부분)
const resultMessage = `
<h2>검색 결과:</h2>
<div>
<h3>상품명: ${query.color} ${query.category}</h3>
<p>사이즈: ${query.size}</p>
<p>가격: 89,000원</p>
</div>
`;
// HTML 응답
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`
<h1>쇼핑몰 상품 검색</h1>
${searchMessage}
${resultMessage}
`);
} else {
// 검색 조건이 없을 때
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`
<h1>상품을 검색해주세요</h1>
<p>예시: /?category=shoes&color=black&size=260</p>
`);
}
});
// 서버 실행
server.listen(8080, () => {
console.log('쇼핑몰 서버가 8080 포트에서 실행 중입니다.');
});
서버를 실행하고, 크롬의 주소창에 http://localhost:8080/?category=shoes&color=black&size=260를 입력해보세요.
'Front > Node.js' 카테고리의 다른 글
| node.js로 API 통신 구현하기 (0) | 2024.12.09 |
|---|---|
| Express 모듈을 사용하여 서버 만들기 (1) | 2024.12.09 |
| Node.js 기본 개념과 특징 (1) | 2024.12.09 |
| 대한민국 공공데이터 포털 사용 가이드 (1) | 2024.11.20 |
| node.js, package.json, npm swiper, npm parcel 설치 및 설정 (0) | 2023.09.27 |