본문 바로가기
프로그래밍

서버 구현 :: node.js + Express

by 로맨틱스터디 2025. 11. 4.
728x90
반응형

"서버를 구현한다"는 말은 꽤 넓은 의미라, 무엇을 하고 싶은 서버인지에 따라 접근이 달라져요.
그래도 처음 시작하는 사람 기준으로 기본적인 웹 서버 구현 절차를 단계별로 정리해드릴게요.


🧩 1. 서버의 개념 이해

서버는 쉽게 말해서 요청(Request)을 받아서 응답(Response)을 보내는 프로그램이에요.

 

예를 들어:

  • 사용자가 브라우저에서 http://example.com 입력 → 요청 전송
  • 서버가 요청을 받아 HTML, JSON 등을 응답 → 브라우저가 보여줌

⚙️ 2. 언어 선택

서버를 만들 수 있는 언어는 많아요:

언어 대표적인 프레임워크 특징
JavaScript (Node.js) Express.js, Fastify 간단하고 빠르게 시작 가능
Python Flask, Django, FastAPI 문법이 쉬워서 입문자에게 좋음
Java Spring Boot 대규모 서비스에 적합
Go net/http, Gin 빠르고 효율적
Rust Actix, Rocket 성능 최강, 하지만 난이도 높음

처음이라면 👉 Python + Flask / Node.js + Express 추천드려요.

 

Q. Node.js 만으로 서버 만들 수 있을까? Express가 꼭 필요한가?

더보기
더보기

많은 초보 개발자들이 헷갈리는 부분인데,
지금 정확히 구분 짓고 가면 나중에 훨씬 이해가 빨라집니다.
하나씩 정리해드릴게요👇


🧩 1️⃣ Node.js만으로도 서버를 만들 수 있을까?

➡️ 가능합니다!
Node.js 자체에도 기본 내장 모듈(http) 이 있어서 --- http.createServer((req, res) => {})
별도의 설치 없이도 서버를 만들 수 있어요.

예시:

// http 모듈로 간단한 서버 만들기
const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Node.js!');
});

server.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

✅ 이렇게도 서버가 돌아갑니다.


⚙️ 2️⃣ 그런데 왜 Express.js를 많이 쓸까?

http 모듈만으로 서버를 만들 수 있지만,
👉 복잡한 기능을 직접 다 처리해야 해서 불편합니다.

 

예를 들어:

  • 라우팅(/user, /login 등 경로 관리)
  • POST 요청(body 데이터) 처리
  • 정적 파일 서빙
  • 에러 처리
  • 미들웨어 관리

이런 걸 매번 직접 코드로 써야 하죠 😓

그래서 등장한 게 Express.js예요.


🚀 3️⃣ Express.js란?

Express.js는 Node.js 위에서 동작하는 웹 프레임워크입니다.

 

📦 설명하자면:

  • Node.js의 http 모듈을 기반으로 만들어졌고,
  • 웹 서버를 더 쉽게 만들 수 있도록 도구 / 규칙(구조)을 제공합니다.

예시 (Express.js 버전)

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

app.get('/', (req, res) => {
  res.send('Hello Express!');
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

➡️ 훨씬 깔끔하고 단순하죠?
라우팅, 요청 파싱, 에러 처리 등을 자동으로 처리해줍니다.


🧠 4️⃣ 프레임워크 vs 라이브러리의 차이

구분 라이브러리 프레임워크
주도권 내가 라이브러리를 호출함 프레임워크가 내 코드를 호출함
구조 내가 구조를 정함 프레임워크가 구조를 정해줌
예시 jQuery, Lodash, React Express.js, Django, Spring
비유 재료만 주는 요리도구 레시피까지 정해주는 요리 키트 🍱

 

➡️ Express.js는 **서버 개발 구조를 정해주는 “프레임워크”**입니다.
(단, 구조가 유연해서 “가벼운 프레임워크”로 불리기도 해요.)


🧩 5️⃣ 결론 요약

질문 답변
Node.js만으로 서버 만들 수 있어? ✅ 가능 (http 모듈 사용)
Express.js는 꼭 설치해야 해? ❌ 필수는 아님, 하지만 대부분 사용
Express.js는 뭐야? Node.js 기반 웹 프레임워크
프레임워크랑 라이브러리 차이? 누가 주도하느냐”의 차이 (Express는 프레임워크)

 


 

이 질문은 진짜 “서버가 어떻게 응답을 주는지”의 핵심을 짚은 질문이에요.
지금처럼 정확히 이해하면, Express나 Flask 같은 프레임워크가 내부에서 뭘 하는지도 완벽히 알게 됩니다.
하나씩 차근차근 풀어드릴게요 👇


🧩 1️⃣ 전체 코드 복습

const http = require('http');

http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello Node.js!');
}).listen(3000);

이건 Node.js 기본 http 모듈로 웹 서버를 만든 코드예요.

  • createServer() → 요청이 들어오면 실행될 콜백 함수를 등록
  • (req, res) → 각각 요청(request) 객체응답(response) 객체
  • res.writeHead(...) → 응답 헤더를 작성
  • res.end(...) → 응답 본문을 보내고 연결 종료

🧠 2️⃣ res.writeHead(statusCode, headers)의 의미

writeHead()는 **HTTP 응답의 "상태 코드(status code)"와 "헤더(headers)"**를 설정하는 함수예요.

형식:

res.writeHead(상태코드, 응답헤더)

예시:

res.writeHead(200, { 'Content-Type': 'text/plain' });

➡️ 이 한 줄이 아래와 같은 HTTP 응답을 만드는 거예요 👇

 
HTTP/1.1 200 OK
Content-Type: text/plain

📜 3️⃣ 첫 번째 인자 200 — 상태 코드 (Status Code)

200은 “요청이 정상적으로 처리됨”을 의미하는 HTTP 상태 코드예요.
즉, **“성공”**을 뜻합니다.

❓ 왜 { Status: 200 } 같은 객체로 안 쓰는가?

→ HTTP 프로토콜에서 상태 코드는 헤더가 아니라 "응답의 첫 줄"에 들어가기 때문이에요.

 

예시로 실제 HTTP 응답을 보면 👇

HTTP/1.1 200 OK
Content-Type: text/plain
  • 200 OK ← 응답의 “상태 줄(status line)
  • Content-Type: text/plain ← 응답의 “헤더(header)
  • (이후 본문이 나옴)

즉,

상태 코드는 헤더와는 별도로 존재하는 정보이기 때문에
writeHead()의 첫 번째 인자로 따로 전달하는 거예요.


📬 4️⃣ 두 번째 인자 { 'Content-Type': 'text/plain' }

이건 **응답 헤더 (Response Header)**를 나타내는 객체예요.
key: value 쌍으로 되어 있습니다.

예시:

헤더 이름 의미
Content-Type 응답 본문의 데이터 타입 (text/plain, text/html, application/json 등)
Content-Length 응답 데이터의 길이
Set-Cookie 쿠키 설정
Cache-Control 캐싱 정책

 

즉,

{ 'Content-Type': 'text/plain' }

은 브라우저에게

“이 응답은 단순한 텍스트야(HTML 아니야)”
라고 알려주는 역할을 합니다.


💬 5️⃣ 왜 항상 200을 쓰는 건가요?

사실 “항상”은 아닙니다.
200은 **정상 처리(OK)**일 때 쓰는 기본 코드고,
요청의 결과에 따라 다른 코드를 써야 해요.


상태 코드 의미
200 성공 (OK)
201 생성됨 (Created)
301 영구 이동 (Redirect)
400 잘못된 요청 (Bad Request)
401 인증 필요 (Unauthorized)
403 접근 금지 (Forbidden)
404 찾을 수 없음 (Not Found)
500 서버 내부 오류 (Internal Server Error)

예를 들어:

if (req.url === '/') {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Home page');
} else {
  res.writeHead(404, { 'Content-Type': 'text/plain' });
  res.end('Not found');
}

✅ 요약 정리

코드 요소 역할 설명
res.writeHead(200, {...}) 응답 상태 + 헤더 설정 200 = 성공 상태 코드
200 상태 코드 (status line) “정상 처리됨”을 의미
{ 'Content-Type': 'text/plain' } 응답 헤더 객체 응답 데이터의 타입을 명시
{ Status: 200 }로 안 쓰는 이유 상태 코드는 헤더가 아니라 응답 첫 줄에 따로 있음  
상태 코드는 왜 200? 성공을 의미하며, 필요 시 404, 500 등으로 변경 가능  

 

 


🧰 3. 예제: Node.js + Express로 서버 구현

아래는 가장 간단한 웹 서버 예제예요.

 

1️⃣ Node.js 설치
https://nodejs.org 에서 설치

 

2️⃣ 새 프로젝트 생성

mkdir my-server
cd my-server
npm init -y
npm install express

 

Q. npm init -y

더보기
더보기

npm init -y는 Node.js 프로젝트를 초기화할 때 사용하는 명령어예요.
하나씩 풀어서 설명드릴게요👇


🧩 npm이 뭐냐면

npm은 Node Package Manager의 약자예요.
Node.js에서 사용하는 **패키지(=라이브러리, 모듈)**를 설치하고 관리하는 도구예요.

 

즉, Node.js 세계에서

“패키지를 설치 / 프로젝트를 관리할 때 쓰는 프로그램”


⚙️ npm init이 하는 일

npm init 명령어는Node.js 프로젝트를 시작할 때 기본 설정을 만드는 명령어예요.

실행하면 이런 대화식 질문이 나와요 👇

name: (my-app)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)

그리고 다 입력을 마치면 package.json 이라는 파일이 생겨요.

 


📦 package.json 파일이란?

이 파일은 프로젝트의 설정 정보 / 의존성(라이브러리) 목록을 담고 있어요.
예를 들어 이런 식이에요 👇

{
  "name": "my-server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {},
  "license": "ISC"
}

⚡ -y 옵션의 의미

-y는 **“yes”**의 약자예요.
즉, npm init -y 하면
위에서 물어보는 질문을 전부 기본값으로 자동 입력하고 바로 package.json을 만들어 줍니다.

➡️ “빠르게 초기 설정만 하고 싶을 때” 사용합니다.


💡 정리

명령어 설명
npm init 프로젝트 설정을 하나씩 물어보면서 생성
npm init -y 모든 값을 기본으로 자동 생성

예를 들어 아래처럼 하면 👇

 
mkdir my-server
cd my-server
npm init -y

➡️ my-server 폴더 안 package.json이 자동으로 생깁니다.

 

그다음에 이런 식으로 라이브러리(express)를 설치하죠 👇

 
npm install express

Q. npm init 질문

더보기
더보기

🧩 npm init 질문 중 주요 항목들

 

1️⃣ entry point: (index.js)

  • 뜻: “이 프로젝트의 **시작 파일(메인 파일)**은 뭐야?”
  • Node.js가 프로젝트를 실행할 때, 가장 먼저 실행자바스크립트 파일을 지정하는 거예요.

예시:

entry point: (index.js)

 

그럼 package.json 안에 이렇게 기록돼요 👇

"main": "index.js"

 

즉, 누군가 이 패키지를 가져다 쓸 때

require('my-package')

라고 하면 index.js가 불러와지는 거예요.

 

💡 요약

entry point = 프로그램이 “여기서부터 시작해!” 하는 파일
(보통 index.js로 두지만, app.jsserver.js로 바꿔도 돼요)


2️⃣ keywords

  • 뜻: “이 프로젝트를 설명하는 검색용 키워드들”
  • npm에 공개할 때 사람들이 찾기 쉽게 해주는 태그 같은 거예요.

예시:

keywords: server, express, api

 

➡️ package.json에는 이렇게 저장돼요:

"keywords": ["server", "express", "api"]

 

💡 요약

keywords = 검색 태그 (npm 등록 시 도움이 됨).
개인 프로젝트라면 그냥 비워둬도 전혀 상관없어요.


3️⃣ license

  • 뜻: “이 프로젝트를 다른 사람이 쓸 때, 어떤 이용 조건으로 허락할까?”
  • 즉, “내 코드 마음대로 써도 돼?” 하는 법적 조건이에요.

예시:

  • MIT자유롭게 사용 가능 (가장 흔함)
  • ISC → MIT랑 거의 비슷 (기본값)
  • GPL → 공개된 코드라면 수정/배포 시 공개 의무 있음
  • UNLICENSED → 외부에 배포 안 할 때 사용

예시 결과

"license": "ISC"

 

💡 요약

license = 내 코드의 사용 허가 조건
개인 공부용이면 그대로 두고, 배포할 때만 신경 쓰면 돼요.


🎯 한눈에 요약

항목 의미 예시 꼭 필요?
entry point 시작 파일 index.js
keywords 검색용 태그 ["server", "api"]
license 코드 사용 조건 "MIT" ✅ (기본값으로 OK)

 

Q. cd

더보기
더보기

cd 명령어는 디렉토리(폴더)를 이동하는 명령어입니다.


📘 정리

  • 명령어: cd
  • 풀네임: change directory
    👉 “디렉토리를 바꾼다”라는 뜻이에요.

💡 예시로 이해하기

예를 들어 이런 구조가 있다고 해요:

my-project/
 ├── index.js
 └── src/
     └── app.js

터미널에서:

cd my-project

➡️ my-project 폴더로 들어감

 
cd src

➡️ my-project/src 폴더로 들어감

 
cd ..

➡️ 한 단계 위로 올라감 (즉, 부모 폴더로 이동)


📂 자주 쓰는 관련 명령어

명령어 설명
pwd 현재 위치(경로)를 보여줌 → print working directory
ls (macOS/Linux) / dir (Windows) 현재 폴더의 파일 목록 보기
cd 폴더명 해당 폴더로 이동
cd .. 상위 폴더로 이동
cd / 루트(최상위) 폴더로 이동
mkdir 폴더명 새 폴더 만들기 (make directory)

💬 즉,

  • cd = 폴더 이동
  • mkdir = 폴더 만들기
  • touch(Mac/Linux) or type nul > 파일명(Windows) = 파일 만들기

 

3️⃣ index.js 파일 생성

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

// GET 요청 처리
app.get('/', (req, res) => {
  res.send('Hello, Server!');
});

// 서버 실행
app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

 

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

더보기
더보기

지금 말씀하신 내용 거의 다 맞아요.
이제 제가 정확히 어떻게 연결되어 있는지 조금만 더 깊게 정리해드릴게요 👇


🧩 1️⃣ require('express')가 하는 일

맞습니다 ✅

const express = require('express');

이건 Node.js의 모듈 시스템(CommonJS) 문법이에요.
즉, "express"라는 이름의 외부 패키지 불러와서(import) 내 파일에서 쓸 수 있게 하는 것이에요.


🔍 실행 순서 요약

  1. require('express')
    → Node.js가 node_modules/express 폴더를 찾아감
  2. 거기서 **index.js (또는 main으로 지정된 파일)**을 읽음
  3. 그 안에서 정의된 코드를 불러와서
    그 결과(=함수)express 변수에 저장

즉,

express 변수 안에는 “Express 프레임워크의 핵심 함수”가 들어있어요.


🧠 2️⃣ express는 뭐냐면…

express는 단순히 **객체/데이터가 아니라 “함수(function)”**입니다.

그래서 아래 코드처럼 **실행()**시켜야 해요 👇

 
const app = express();

⚙️ 3️⃣ express()는 뭘 하는 함수냐면

이건 Express 애플리케이션 객체(app)”를 생성하는 함수예요.

 

이 객체가 바로:

  • 라우팅(/, /users, /login 등) 처리
  • 미들웨어 등록
  • 요청/응답 관리
  • 서버 실행 (app.listen())

같은 일을 담당합니다.

 

즉, express()는

“Express 프레임워크 엔진을 초기화해서 내 앱을 위한 서버 인스턴스를 만들어주는 함수”예요.


🧱 4️⃣ app은 뭐냐면

app은 express()가 반환한 서버 객체입니다.

 

이걸 이용해서 서버 기능 정의해요 👇

app.get('/', (req, res) => {
  res.send('Hello Express!');
});

이런 식으로 **라우트(route)**를 등록하거나,

 

미들웨어를 추가하거나, 서버를 실행합니다 👇

app.listen(port, () => {
  console.log(`Server running on http://localhost:${port}`);
});

📦 5️⃣ 그럼 “express는 코드가 써진 파일들이 있는 거야?” → ✅ 맞아요!

express는 npm에서 설치된 **패키지(라이브러리)**예요.

즉, 내가 작성한 코드가 아니라, 누군가 만들어둔 코드 묶음이에요.

 

설치 경로는 대개 이렇습니다 👇

my-project/
 ├── index.js         ← 내가 작성한 서버 코드
 ├── package.json
 └── node_modules/
     └── express/     ← 여기에 express 코드가 들어있음

그래서 require('express') 하면
Node.js가 node_modules/express 폴더 안에 있는 코드를 읽어옵니다.


🔁 요약

코드 설명
require('express') express 패키지(=외부 코드)를 불러옴
express express 모듈이 export한 “함수”
express() express 서버 애플리케이션 객체 생성
app 생성된 express 애플리케이션 인스턴스
app.listen() 서버를 실행시킴

🧠 정리하자면:

require('express') → express 모듈의 코드를 읽어옴
express() → 그 모듈의 “생성 함수” 실행
app → 내가 조작할 수 있는 express 서버 객체

 

Q. app.listen(port, () => {})

더보기
더보기

app.listen()은 Express 서버를 실제로 실행하는 함수이고,
그 뒤에 붙은 () => {} 콜백 함수는 말씀하신 대로 서버가 포트에 성공적으로 연결된 후 실행되는 코드예요.

이걸 조금 더 깊게 정리해드릴게요 👇


🧩 1️⃣ app.listen()의 역할

Express에서 app.listen()은
👉 HTTP 서버를 시작(start) 하는 함수예요.

즉,

“이 서버를 특정 포트(port) 번호로 열어라!”
라는 명령이에요.


🔧 예시

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

app.listen(port, () => {
  console.log(`Server running on http://localhost:${port}`);
});

 

실행하면 콘솔에 이렇게 나와요 👇

Server running on http://localhost:3000

이제 브라우저에서 http://localhost:3000 접속하면
이 서버로 요청이 들어옵니다.


⚙️ 2️⃣ 내부적으로 무슨 일이 일어나냐면

app.listen()은 사실 아래와 거의 동일한 일을 합니다 👇

 
const http = require('http'); const server = http.createServer(app); server.listen(port, callback);

즉,

  • Node.js의 기본 http 모듈을 사용해서
  • Express의 app을 **요청 핸들러(request handler)**로 등록하고
  • 그걸 지정한 포트로 “청취(listen)”하도록 만드는 거예요.

💡 그래서 이름이 listen = “요청을 듣는다” 인 거예요.
(“요청을 기다리는 상태로 만든다”라는 뜻)


🧠 3️⃣ app.listen(port, callback) 매개변수 설명

매개변수역할예시
port 서버가 열릴 포트 번호 3000 → http://localhost:3000
callback 서버가 실행된 후 호출되는 함수 () => console.log('서버 실행!')

그래서 이건 정확히 이렇게 읽힙니다 👇

“3000번 포트로 서버를 열고, 실행이 완료되면 콜백 함수를 실행해라.”


📡 흐름으로 보면 이렇게 돼요

 
1️⃣ node index.js 실행 2️⃣ app.listen(3000, callback) 3️⃣ Express가 내부적으로 http 서버 생성 4️⃣ 서버가 3000번 포트에 연결 시도 5️⃣ 연결 성공 → callback 실행 6️⃣ 이제 브라우저 요청 대기 상태

🧱 4️⃣ 예시로 더 명확히 보기

 
const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Hello Express!'); }); // 서버 실행 app.listen(3000, () => { console.log('✅ 서버가 3000번 포트에서 실행 중입니다!'); });

실행하면:

 
서버가 3000 포트에서 실행 중입니다!

그리고 브라우저에서 http://localhost:3000을 열면
“Hello Express!”가 뜹니다.


✅ 정리

코드역할
app.listen() Express 서버 시작
port 서버가 열릴 포트 번호
callback 서버 실행 완료 시 실행될 함수
내부 동작 http.createServer(app).listen(port, callback) 과 거의 동일
이름 뜻 "요청을 듣는다(listen)" — 즉, 연결 대기 상태

💬 요약 한 줄

app.listen(port, callback)
→ “이 포트에서 요청을 기다려라. 연결되면 이 콜백 함수를 실행해라.”

 

4️⃣ 실행

node index.js

브라우저에서 http://localhost:3000 접속 → “Hello, Server!” 출력 🎉


🧱 4. 서버가 하는 일들

서버는 다음과 같은 역할을 수행해요:

  • 요청 처리 (예: 로그인, 회원가입, 데이터 조회)
  • DB와 통신 (MySQL, MongoDB 등)
  • 파일 업로드 / 다운로드
  • API 제공
  • 보안 관리 (인증, 인가 등)

🚀 5. 다음 단계

서버 기초를 다지고 나면 이런 걸 배워가면 좋아요:

  • REST API / GraphQL 개념
  • 데이터베이스 연결 (예: PostgreSQL, MongoDB)
  • 환경 변수 관리 (dotenv)
  • 배포 (AWS, Render, Vercel 등)
  • Docker로 서버 컨테이너화
728x90
반응형