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 기본 개념과 특징 (0) | 2024.12.09 |
대한민국 공공데이터 포털 사용 가이드 (0) | 2024.11.20 |
node.js, package.json, npm swiper, npm parcel 설치 및 설정 (0) | 2023.09.27 |