프로그래밍/Node.js

Node.js 정복 가이드: 서버 개발의 새로운 패러다임을 만나다

shimdh 2025. 2. 18. 09:37
728x90

1. Node.js란 무엇인가?: 새로운 시대의 시작

Node.js는 서버 측에서 자바스크립트를 실행할 수 있게 해주는 오픈 소스 런타임 환경입니다. 기존에 자바스크립트는 웹 브라우저 내에서만 동작하는 클라이언트 사이드 스크립팅 언어로 여겨졌습니다. 하지만 Node.js의 등장으로 자바스크립트는 서버 개발 영역까지 그 활용 범위를 넓히게 되었습니다. 이러한 변화는 웹 애플리케이션 개발 방식에 일대 혁신을 가져왔습니다.

2. Node.js의 역사: 혁신은 어떻게 시작되었나?

2.1 탄생 배경: 웹 애플리케이션의 한계를 넘어서

Node.js는 2009년 Ryan Dahl에 의해 처음 발표되었습니다. Ryan Dahl은 당시 웹 애플리케이션이 가지고 있던 한계, 특히 동시성(Concurrency) 처리의 비효율성을 극복하고자 했습니다. 이를 위해 더 효율적이고 확장 가능한 서버 사이드 프로그래밍 환경을 구축하는 것을 목표로 Node.js를 개발했습니다. Node.js는 Google Chrome의 V8 자바스크립트 엔진을 기반으로 만들어졌습니다. V8 엔진은 자바스크립트 코드를 빠르게 실행하는 것으로 정평이 나 있었고, 이는 Node.js의 성능 확보에 큰 기여를 했습니다.

2.2 주요 이정표: 지속적인 성장과 발전

Node.js는 출시 이후 지속적인 발전을 거듭하며 현재의 모습을 갖추게 되었습니다. 주요 발전 과정을 간략히 살펴보면 다음과 같습니다.

  1. 2009년: 초기 버전 출시

    • Node.js의 첫 번째 버전은 매우 기본적인 기능만을 제공했습니다. 가장 핵심적인 기능은 간단한 HTTP 서버를 구축할 수 있는 기능이었습니다.
  2. 2010년: npm 출시

    • Node.js 생태계 확장에 결정적인 역할을 한 패키지 관리 시스템, npm(Node Package Manager)이 도입되었습니다. npm을 통해 개발자들은 수많은 오픈 소스 라이브러리와 모듈을 손쉽게 공유하고 재사용할 수 있게 되었습니다.
  3. 2010년 ~ 2014년: v0.x 시리즈

    • 이 시기 동안 Node.js는 v0.x 버전을 거치면서 다양한 기능 개선과 안정화 작업을 진행했습니다. 성능 향상, 새로운 API 추가, 버그 수정 등이 이루어졌고, 점점 더 많은 기업들이 Node.js를 실제 서비스 개발에 채택하기 시작했습니다.
  4. 2015년: LTS 버전 도입

    • Node.js는 안정적인 장기 지원(Long Term Support, LTS) 버전을 도입하여 엔터프라이즈 환경에서의 신뢰도를 높였습니다. LTS 버전은 장기간에 걸쳐 유지 보수 및 보안 업데이트가 제공되기 때문에, 안정성을 중시하는 기업들이 안심하고 Node.js를 사용할 수 있는 기반이 마련되었습니다.
  5. 현재:

    • Node.js는 최신 기술 트렌드를 적극적으로 반영하며 지속적으로 발전하고 있습니다. 실시간 애플리케이션 개발, 마이크로서비스 아키텍처 지원 강화 등 현대 웹 개발의 요구 사항을 충족하기 위한 기능들이 추가되고 개선되고 있습니다.

이러한 발전을 통해 Node.js는 단순한 런타임 환경을 넘어 현대 웹 개발의 핵심 기술로 자리매김했습니다.

3. Node.js의 특징: 강력함과 유연함의 비결

Node.js는 여러 독특한 특징을 가지고 있습니다. 이러한 특징들은 개발자들이 Node.js를 선택하는 주요 이유이자, Node.js가 다른 서버 사이드 플랫폼과 차별화되는 지점입니다.

3.1 비동기 이벤트 기반 (Asynchronous Event-Driven)

Node.js의 가장 큰 특징 중 하나는 비동기 이벤트 기반 아키텍처입니다. 이는 Node.js가 요청을 처리하는 방식의 핵심입니다. 비동기 프로그래밍 모델을 채택함으로써, Node.js는 특정 작업이 완료될 때까지 기다리지 않고 다른 작업을 동시에 수행할 수 있습니다.

동작 원리 예시

예를 들어, 사용자가 웹 페이지를 요청하면 서버는 해당 요청을 처리하면서 데이터베이스 쿼리를 보내거나 파일을 읽어야 할 수 있습니다. 동기식 모델에서는 데이터베이스 응답이나 파일 읽기가 완료될 때까지 다른 요청을 처리할 수 없습니다. 하지만 Node.js의 비동기식 모델에서는 데이터베이스 쿼리나 파일 읽기 요청을 보낸 후, 그 결과를 기다리지 않고 바로 다른 클라이언트의 요청을 처리할 수 있습니다. 데이터베이스 응답이나 파일 읽기가 완료되면, 이벤트 루프가 이를 감지하고 적절한 콜백 함수를 실행하여 후속 처리를 진행합니다.

예제: 파일 읽기와 동시에 HTTP 요청 처리

const fs = require('fs');
const http = require('http');

http.createServer((req, res) => {
  // 파일을 비동기적으로 읽습니다.
  fs.readFile('myFile.txt', (err, data) => {
    if (err) throw err;
    console.log('파일 읽기 완료:', data);
  });

  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('파일을 읽는 동안 HTTP 요청 처리!\n');
}).listen(8080);

위 예제에서는 myFile.txt 파일을 읽는 동안에도 HTTP 요청을 처리하여 즉시 응답을 보냅니다. 파일 읽기가 완료되면 콘솔에 해당 내용이 출력됩니다. 이처럼 Node.js는 I/O 작업이 많은 환경, 즉 네트워크 요청, 파일 시스템 접근, 데이터베이스 쿼리 등이 빈번하게 발생하는 환경에서 높은 성능을 발휘합니다.

3.2 자바스크립트 언어 사용 (JavaScript Everywhere)

Node.js는 서버 사이드 로직을 작성하는 데 자바스크립트를 사용합니다. 이는 프론트엔드와 백엔드 개발에 모두 동일한 언어인 자바스크립트를 사용할 수 있음을 의미합니다.

이점

  • 생산성 향상: 개발자는 새로운 언어를 배울 필요 없이 익숙한 자바스크립트를 사용하여 서버 개발을 할 수 있습니다.
  • 학습 곡선 완화: 프론트엔드 개발자가 서버 개발에 쉽게 참여할 수 있고, 반대의 경우도 마찬가지입니다.
  • 코드 재사용: 프론트엔드와 백엔드 간에 코드를 공유하여 개발 효율성을 높일 수 있습니다. 예를 들어, 데이터 유효성 검사 로직이나 유틸리티 함수 등을 양쪽에서 재사용할 수 있습니다.

예제: 프론트엔드와 백엔드에서 동일한 데이터 유효성 검사 로직 사용

// validation.js (공유 모듈)
function isValidEmail(email) {
  // 이메일 유효성 검사 로직
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function isValidPassword(password) {
  // 비밀번호 유효성 검사 로직 (최소 8자 이상)
  return password.length >= 8;
}

module.exports = { isValidEmail, isValidPassword }; // 모듈로 내보내기

// server.js (백엔드)
const { isValidEmail, isValidPassword } = require('./validation');

// ... 서버 로직에서 isValidEmail, isValidPassword 함수 사용 ...
if (!isValidEmail(userEmail)) {
  // 이메일이 유효하지 않을 때 처리
}

if (!isValidPassword(userPassword)) {
  // 비밀번호가 유효하지 않을 때 처리
}

// client.js (프론트엔드)
// ... 클라이언트에서 isValidEmail, isValidPassword 함수 사용 ... (브라우저 환경에 맞게 모듈 로딩 방식 조정)

위 예제에서는 이메일과 비밀번호 유효성 검사 로직을 validation.js라는 공유 모듈에 정의하고, 이를 서버와 클라이언트에서 모두 재사용합니다. 이를 통해 코드 중복을 줄이고 유지보수성을 높일 수 있습니다.

예제: 프론트엔드와 백엔드에서 날짜/시간 포맷팅 함수 공유

// dateUtils.js (공유 모듈)
function formatDate(date) {
  const year = date.getFullYear();
  const month = (date.getMonth() + 1).toString().padStart(2, '0');
  const day = date.getDate().toString().padStart(2, '0');
  return `${year}-${month}-${day}`;
}

module.exports = { formatDate };

// server.js (백엔드)
const { formatDate } = require('./dateUtils');
// ... 서버에서 formatDate 함수를 사용하여 날짜 포맷팅 ...
const formattedDate = formatDate(new Date()); // 예: "2023-12-20"

// client.js (프론트엔드)
// ... 클라이언트에서 formatDate 함수를 사용하여 날짜 포맷팅 ...

3.3 npm (Node Package Manager)

Node.js는 npm이라는 강력하고 편리한 패키지 관리 시스템을 제공합니다. npm은 Node.js의 핵심 구성 요소 중 하나로, Node.js 설치 시 함께 설치됩니다.

주요 기능

  • 패키지 설치: 전 세계 개발자들이 만든 수많은 오픈 소스 라이브러리와 모듈을 손쉽게 설치할 수 있습니다.
  • 패키지 관리: 프로젝트에서 사용하는 패키지들의 버전 관리, 의존성 관리를 자동화합니다.
  • 패키지 공유: 개발자가 직접 만든 패키지를 npm 레지스트리에 게시하여 다른 개발자들과 공유할 수 있습니다.

예제: express 웹 프레임워크 설치

npm install express

위 명령어 하나로 express 웹 프레임워크를 프로젝트에 설치할 수 있습니다.

예제: lodash 라이브러리를 사용하여 배열에서 중복된 요소 제거

  1. lodash 라이브러리 설치:
npm install lodash
  1. 코드에서 lodash 사용:
const _ = require('lodash');

const myArray = [1, 2, 2, 3, 4, 4, 5];
const uniqueArray = _.uniq(myArray);

console.log(uniqueArray); // 출력: [1, 2, 3, 4, 5]

위 예제에서는 lodash 라이브러리의 uniq 함수를 사용하여 배열에서 중복된 요소를 제거합니다. npm을 사용하면 이처럼 유용한 라이브러리들을 간편하게 설치하고 활용할 수 있습니다.

3.4 모듈화 (Modularity)

Node.js는 모듈 시스템을 기반으로 동작합니다. 모듈 시스템은 코드를 기능별로 나누어 작성하고, 이를 모듈 단위로 불러와 사용할 수 있도록 하는 구조입니다.

이점

  • 코드 재사용성 향상: 잘 정의된 모듈은 다른 프로젝트에서도 쉽게 재사용할 수 있습니다.
  • 유지보수성 향상: 기능별로 코드가 분리되어 있어, 특정 기능을 수정하거나 개선할 때 해당 모듈만 수정하면 되므로 유지보수가 용이합니다.
  • 코드 가독성 향상: 코드가 논리적으로 분리되어 있어 전체적인 구조를 파악하기 쉽고, 개별 모듈의 코드를 이해하기도 수월합니다.

예제: 기능별 모듈화

// math.js (덧셈, 뺄셈 기능을 제공하는 모듈)
exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;

// logger.js (로그 출력 모듈)
exports.log = (message) => console.log(`[LOG] ${message}`);

// app.js (math, logger 모듈 사용)
const math = require('./math');
const logger = require('./logger');

const sum = math.add(5, 3);
const difference = math.subtract(10, 4);

logger.log(`Sum: ${sum}`);       // 출력: [LOG] Sum: 8
logger.log(`Difference: ${difference}`); // 출력: [LOG] Difference: 6

위 예제에서는 덧셈/뺄셈 기능을 math.js 모듈로, 로그 출력 기능을 logger.js 모듈로 분리했습니다. app.js에서는 require 함수를 사용하여 이 모듈들을 불러와 사용합니다.

예제: 데이터베이스 쿼리 모듈화

// db.js (데이터베이스 쿼리 모듈)
const mysql = require('mysql'); // 예시로 mysql 모듈 사용

const connection = mysql.createConnection({
  // 데이터베이스 연결 설정
});

exports.getUserById = (userId, callback) => {
  connection.query('SELECT * FROM users WHERE id = ?', [userId], callback);
};

// app.js
const db = require('./db');

db.getUserById(1, (err, results) => {
  if (err) throw err;
  console.log(results); // 사용자 정보 출력
});

위 예제에서는 데이터베이스 쿼리 관련 로직을 db.js 모듈로 분리했습니다. 이를 통해 데이터베이스 관련 코드를 한 곳에서 관리할 수 있어 유지보수가 용이해집니다.

3.5 확장성 (Scalability)

Node.js는 뛰어난 확장성을 제공합니다. 단일 스레드, 비동기 이벤트 기반 모델을 사용함에도 불구하고, Node.js는 여러 기술을 활용하여 대규모 애플리케이션에서도 높은 성능을 유지할 수 있습니다.

확장성 확보 방법

  • 클러스터링(Clustering): Node.js는 cluster 모듈을 제공하여 멀티 코어 환경에서 애플리케이션의 성능을 극대화할 수 있습니다. cluster 모듈은 마스터 프로세스와 여러 워커 프로세스를 생성하여 요청을 분산 처리합니다.
  • 로드 밸런싱(Load Balancing): 여러 Node.js 인스턴스를 실행하고, 로드 밸런서를 사용하여 요청을 분산할 수 있습니다. 이를 통해 단일 인스턴스에 과부하가 걸리는 것을 방지하고, 전체 시스템의 가용성을 높일 수 있습니다.
  • 마이크로서비스 아키텍처: 애플리케이션을 작은 서비스 단위로 분리하여 개발하고 배포하는 마이크로서비스 아키텍처를 적용할 수 있습니다. 각 서비스는 독립적으로 확장 가능하며, 특정 서비스에 문제가 발생하더라도 다른 서비스에 영향을 미치지 않습니다.

예제: cluster 모듈을 사용한 멀티 코어 활용

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length; // CPU 코어 개수

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // CPU 코어 개수만큼 워커 생성
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
    cluster.fork(); //워커가 죽으면 다시 생성
  });
} else {
  // 워커 프로세스에서 HTTP 서버 실행
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

위 예제는 cluster 모듈을 사용하여 CPU 코어 개수만큼 워커 프로세스를 생성합니다. 각 워커 프로세스는 독립적으로 HTTP 서버를 실행하여 요청을 처리합니다.

3.6 활발한 커뮤니티와 생태계 (Community and Ecosystem)

Node.js는 매우 크고 활발한 개발자 커뮤니티를 보유하고 있습니다. 이는 Node.js의 큰 장점 중 하나입니다.

커뮤니티와 생태계의 이점

  • 풍부한 자료: 온라인 상에 Node.js 관련 튜토리얼, 문서, 가이드 등이 풍부하게 존재하여, 학습과 문제 해결에 도움을 줍니다.
  • 다양한 오픈 소스 라이브러리: npm을 통해 수많은 오픈 소스 라이브러리를 사용할 수 있으며, 이는 개발 생산성을 크게 향상시킵니다.
  • 빠른 기술 발전: 커뮤니티 주도로 새로운 기술과 도구들이 빠르게 개발되고 공유됩니다.
  • 지원 및 협업: 문제가 발생했을 때 커뮤니티를 통해 도움을 얻을 수 있고, 다른 개발자들과 협업할 수 있는 기회가 많습니다.

3.7 단일 스레드 (Single-Threaded)

Node.js는 기본적으로 단일 스레드 모델을 사용합니다. 즉, 하나의 프로세스 내에서 하나의 스레드만이 자바스크립트 코드를 실행합니다.

단일 스레드의 장단점

  • 장점:

    • 간단한 프로그래밍 모델: 멀티 스레딩 환경에서 발생하는 복잡한 동기화 문제를 고려할 필요가 없어, 프로그래밍 모델이 단순합니다.
    • 적은 메모리 사용: 각 스레드는 자체적인 메모리 공간을 필요로 하는데, 단일 스레드 모델은 이러한 메모리 오버헤드가 적습니다.
  • 단점:

    • CPU 집약적인 작업에 불리: 하나의 스레드에서 모든 작업을 처리하기 때문에, CPU 연산을 많이 필요로 하는 작업에서는 성능 저하가 발생할 수 있습니다. (하지만, 워커 스레드 모듈로 CPU 바운드 작업도 멀티스레드로 처리 가능)

이벤트 루프와의 관계

Node.js는 단일 스레드 모델의 단점을 극복하기 위해 이벤트 루프(Event Loop)를 사용합니다. 이벤트 루프는 비동기 I/O 작업을 효율적으로 처리할 수 있도록 해주는 핵심 메커니즘입니다. 이벤트 루프는 논블로킹 I/O(Non-blocking I/O)를 사용하여, I/O 작업이 완료될 때까지 기다리지 않고 다른 작업을 계속 수행할 수 있습니다.

3.8 빠른 속도 (High Performance)

Node.js는 Google Chrome의 V8 자바스크립트 엔진 위에서 실행됩니다. V8 엔진은 자바스크립트 코드를 기계어로 직접 컴파일하여 매우 빠른 실행 속도를 제공합니다. 또한, 앞서 설명한 비동기 이벤트 기반 모델과 논블로킹 I/O 덕분에 I/O 작업이 많은 환경에서도 뛰어난 성능을 발휘합니다.

3.9 크로스 플랫폼 지원 (Cross-Platform)

Node.js는 Windows, macOS, Linux 등 다양한 운영체제에서 실행 가능합니다. 이는 Node.js로 개발된 애플리케이션이 특정 플랫폼에 종속되지 않음을 의미합니다. 개발자는 한 번의 코드 작성으로 여러 플랫폼을 지원하는 애플리케이션을 만들 수 있어 개발 효율성이 높아집니다.

3.10 RESTful API 구축 용이성

Node.js는 RESTful API를 쉽게 구축할 수 있는 구조를 가지고 있어 클라이언트-서버 아키텍처에 적합합니다. 특히, express와 같은 웹 프레임워크를 사용하면 RESTful API 개발이 더욱 간편해집니다. 또한, Node.js는 JSON 형식의 데이터를 쉽게 처리할 수 있어 웹 서비스 개발에 매우 유용합니다.

예제: express를 사용한 간단한 RESTful API

const express = require('express');
const app = express();

app.get('/users/:id', (req, res) => {
  const userId = req.params.id;
  // 데이터베이스에서 userId에 해당하는 사용자 정보 조회
  // ...
  res.json({ id: userId, name: 'John Doe' }); // JSON 응답
});

app.listen(3000);

위 예제는 express 프레임워크를 사용하여 /users/:id 경로로 GET 요청이 왔을 때 사용자 정보를 JSON 형식으로 응답하는 간단한 RESTful API를 보여줍니다.

3.11 마이크로서비스 아키텍처 지원

Node.js는 마이크로서비스 아키텍처를 구축하는 데 매우 적합한 플랫폼입니다. 마이크로서비스 아키텍처는 복잡한 애플리케이션을 작고 독립적인 여러 개의 서비스로 나누어 개발하고 배포하는 방식입니다.

Node.js가 마이크로서비스에 적합한 이유

  • 가벼움: Node.js 애플리케이션은 상대적으로 가볍고 빠르게 실행되기 때문에, 각 마이크로서비스를 독립적으로 배포하고 운영하는 데 유리합니다.
  • 빠른 개발 속도: Node.js의 간결함과 npm 생태계의 풍부한 라이브러리 덕분에 마이크로서비스를 빠르게 개발할 수 있습니다.
  • 확장성: 각 마이크로서비스는 독립적으로 확장 가능하며, Node.js의 클러스터링, 로드 밸런싱 기능을 활용하여 트래픽 증가에 대응할 수 있습니다.
  • 기술 스택 다양성: 각 마이크로서비스는 독립적으로 기술 스택을 선택할 수 있습니다. 예를 들어, 특정 서비스는 Node.js로 개발하고, 다른 서비스는 Python이나 Go로 개발할 수 있습니다.

예제: 사용자 인증과 결제 시스템을 별도의 마이크로서비스로 구성

  • 사용자 인증 서비스 (auth-service): 사용자 로그인, 회원가입, 토큰 발급 등을 담당
  • 결제 서비스 (payment-service): 결제 처리, 결제 내역 조회 등을 담당
  • 상품 서비스 (product-service): 상품 정보 조회, 상품 등록, 수정, 삭제 등을 담당

각 서비스는 독립적인 Node.js 애플리케이션으로 개발되며, 필요에 따라 다른 서비스와 API를 통해 통신합니다.

예제: auth-service의 사용자 인증 API

// auth-service/index.js
const express = require('express');
const app = express();

app.post('/login', (req, res) => {
  // 사용자 인증 로직 (예: 데이터베이스에서 사용자 확인)
  // ...
  res.json({ token: 'your_jwt_token' }); // 인증 성공 시 JWT 토큰 발급
});

app.listen(4001);

예제: payment-service의 결제 처리 API

// payment-service/index.js
const express = require('express');
const app = express();

app.post('/pay', (req, res) => {
  // 결제 처리 로직 (예: 외부 결제 게이트웨이와 연동)
  // ...
  res.json({ status: 'success', transactionId: '12345' }); // 결제 성공
});

app.listen(4002);

4. 실전 예제: Node.js로 HTTP 서버 구축하기

Node.js의 기본적인 동작 방식을 이해하기 위해 간단한 HTTP 서버를 만들어 보겠습니다.

const http = require('http'); // 내장 http 모듈 로드

// http.createServer는 HTTP 서버 객체를 생성합니다.
// 이 객체는 들어오는 HTTP 요청을 처리하고, 응답을 보냅니다.
// (req, res) => { ... } 부분은 콜백 함수입니다.
// 이 콜백 함수는 HTTP 요청이 들어올 때마다 호출됩니다.
// req는 요청 객체(request), res는 응답 객체(response)입니다.
const server = http.createServer((req, res) => {
  // res.statusCode는 HTTP 응답 상태 코드를 설정합니다.
  // 200은 성공을 의미합니다.
  res.statusCode = 200;

  // res.setHeader는 HTTP 응답 헤더를 설정합니다.
  // 'Content-Type', 'text/plain'은 응답의 내용이 일반 텍스트임을 나타냅니다.
  res.setHeader('Content-Type', 'text/plain');

  // res.end는 HTTP 응답 본문을 보내고, 연결을 종료합니다.
  res.end('안녕하세요! 이곳은 간단한 HTTP 서버입니다.\n');
});

// server.listen은 서버를 시작하고, 지정된 포트에서 들어오는 연결을 기다립니다.
// 3000은 포트 번호입니다.
// () => { ... } 부분은 콜백 함수입니다.
// 이 콜백 함수는 서버가 시작된 후 호출됩니다.
server.listen(3000, () => {
  // console.log는 콘솔에 메시지를 출력합니다.
  console.log('서버가 http://localhost:3000/ 에서 실행 중입니다.');
});

위 코드는 "안녕하세요! 이곳은 간단한 HTTP 서버입니다."라는 메시지를 출력하는 매우 기본적인 HTTP 서버를 생성합니다. 이처럼 Node.js를 사용하면 단 몇 줄의 코드만으로도 강력한 네트워크 애플리케이션을 구축할 수 있습니다.

예제: URL에 따라 다른 응답 보내기

const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');

  if (req.url === '/') {
    res.end('홈페이지입니다.\n');
  } else if (req.url === '/about') {
    res.end('회사 소개 페이지입니다.\n');
  } else {
    res.statusCode = 404;
    res.end('페이지를 찾을 수 없습니다.\n');
  }
});

server.listen(3000, () => {
  console.log('서버가 http://localhost:3000/ 에서 실행 중입니다.');
});

위 예제는 요청 URL에 따라 다른 응답을 보내도록 기능을 추가한 것입니다. /로 접속하면 "홈페이지입니다.", /about으로 접속하면 "회사 소개 페이지입니다."라는 메시지를 출력합니다. 그 외의 URL로 접속하면 "페이지를 찾을 수 없습니다."라는 메시지와 함께 404 상태 코드를 반환합니다.

예제: 쿼리 파라미터에 따라 다른 응답 보내기

const http = require('http');
const url = require('url');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');

  const queryObject = url.parse(req.url, true).query;
  const name = queryObject.name || 'Guest'; // 쿼리 파라미터에서 name 값을 가져옴

  res.end(`안녕하세요, ${name}님!\n`);
});

server.listen(3000, () => {
  console.log('서버가 http://localhost:3000/ 에서 실행 중입니다.');
});

이제 http://localhost:3000/?name=Node.js로 접속하면 "안녕하세요, Node.js님!"이라는 응답을 볼 수 있습니다. 쿼리 파라미터 name의 값에 따라 동적으로 응답 메시지가 변경되는 것을 확인할 수 있습니다.

5. 결론: Node.js와 함께하는 서버 개발의 미래

Node.js는 현대 웹 개발, 특히 서버 개발 영역에서 빼놓을 수 없는 핵심 기술로 자리 잡았습니다. 비동기 이벤트 기반 아키텍처, 자바스크립트 언어 사용, 강력한 npm 생태계, 뛰어난 확장성 등 Node.js가 가진 여러 장점들은 개발자와 기업 모두에게 매력적인 선택지를 제공합니다.

실시간 웹 애플리케이션, RESTful API, 마이크로서비스 등 최신 개발 트렌드와도 잘 맞아떨어지는 Node.js는 앞으로도 그 중요성이 더욱 커질 것으로 예상됩니다. 이 가이드가 Node.js의 세계로 입문하는 데 훌륭한 길잡이가 되었기를 바라며, Node.js를 통해 서버 개발의 새로운 가능성을 마음껏 탐험해 보시기 바랍니다.

728x90