Node.js HTTP 모듈 마스터하기: 서버·REST API 구축 및 요청 처리
Source: Dev.to
HTTP 모듈 소개
현대 웹 애플리케이션은 클라이언트와 서버 간의 통신에 크게 의존합니다. REST API를 구축하든, 브라우저 요청을 처리하든, 파일을 제공하든, Node.js의 HTTP 모듈을 이해하는 것은 모든 백엔드 개발자가 반드시 마스터해야 할 기본 기술입니다.
Node.js는 외부 패키지를 설치하지 않고도 서버를 만들고, 요청·응답을 관리하며, 라우팅을 처리하고, 대용량 데이터를 효율적으로 스트리밍할 수 있는 내장 HTTP 모듈을 제공합니다.
이 글에서는 실용적인 예제와 설명, 모범 사례, 실제 사용 시나리오를 통해 Node.js HTTP 모듈을 깊이 있게 살펴보겠습니다.
HTTP란?
HyperText Transfer Protocol의 약자이며, 다음과 같은 주체 간 통신에 사용되는 프로토콜입니다.
- 브라우저와 웹 서버
- 프론트엔드와 백엔드 애플리케이션
- API와 클라이언트
웹 사이트에 접속하면:
- 브라우저가 HTTP 요청을 보냅니다.
- 서버가 이를 처리합니다.
- 서버가 HTTP 응답을 반환합니다.
주요 기능
- 요청을 처리하고 응답을 보내는 HTTP 서버 생성
- 다른 서버에 HTTP 요청 전송
- 다양한 HTTP 메서드(GET, POST, PUT, DELETE 등) 처리
- 요청·응답 헤더 다루기
- 대용량 페이로드를 위한 스트리밍 처리
Node.js에서는 require() 함수를 사용해 모듈을 가져옵니다.
const http = require('http');
ES 모듈을 사용할 경우:
import http from 'http';
간단한 Node.js 서버 만들기
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Hello, World!');
});
server.listen(3000, () => {
console.log('Server running on port 3000');
});
http.createServer()→ HTTP 서버를 생성합니다.req→ 요청 객체res→ 응답 객체
res.writeHead()
- 상태 코드와 헤더를 설정합니다.
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end()
- 응답을 전송하고 연결을 종료합니다.
res.end('Hello World');
server.listen()
- 서버를 시작합니다.
server.listen(3000);
위 코드를 server.js 파일에 저장하고 실행합니다.
node server.js
브라우저에서 http://localhost:3000에 접속하면 응답을 확인할 수 있습니다.
HTTP 헤더
응답에 추가 정보를 포함하려면 헤더를 사용합니다. res.writeHead() 메서드로 상태 코드와 헤더를 설정합니다.
const http = require('http');
const server = http.createServer((req, res) => {
// 상태 코드와 여러 헤더 설정
res.writeHead(200, {
'Content-Type': 'text/html',
'X-Powered-By': 'Node.js',
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Set-Cookie': 'sessionid=abc123; HttpOnly'
});
res.end(`
## Hello, World!
`);
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
주요 상태 코드
| 코드 | 메시지 | 설명 |
|---|---|---|
| 200 | OK | 성공적인 HTTP 요청에 대한 표준 응답 |
| 201 | Created | 요청이 성공적으로 처리되어 새로운 리소스가 생성됨 |
| 301 | Moved Permanently | 리소스가 새로운 URL로 영구 이동됨 |
| 400 | Bad Request | 클라이언트 오류로 인해 서버가 요청을 처리할 수 없음 |
| 401 | Unauthorized | 인증이 필요함 |
| 403 | Forbidden | 서버가 요청을 허가하지 않음 |
| 404 | Not Found | 요청한 리소스를 찾을 수 없음 |
| 500 | Internal Server Error | 예상치 못한 오류 발생 |
일반 헤더 설명
- Content-Type: 콘텐츠의 미디어 타입 지정(e.g.,
text/html,application/json) - Content-Length: 응답 본문의 바이트 길이
- Location: 리다이렉션 시 사용(3xx 상태 코드와 함께)
- Set-Cookie: 클라이언트에 쿠키 설정
- Cache-Control: 캐시 동작 지시자
- Access-Control-Allow-Origin: CORS 지원을 위한 헤더
요청 헤더 접근
req.headers 객체를 통해 요청 헤더에 접근할 수 있습니다.
const http = require('http');
const server = http.createServer((req, res) => {
// 모든 요청 헤더 로그 출력
console.log('Request Headers:', req.headers);
// 특정 헤더(대소문자 구분 없음) 가져오기
const userAgent = req.headers['user-agent'];
const acceptLanguage = req.headers['accept-language'];
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`User-Agent: ${userAgent}\nAccept-Language: ${acceptLanguage}`);
});
server.listen(3000);
URL 및 쿼리 문자열 처리
Node.js는 URL과 쿼리 문자열을 다루는 내장 모듈을 제공하여, URL 구성 요소와 파라미터를 쉽게 파싱할 수 있게 합니다. req.url 속성에는 요청된 전체 URL 문자열(쿼리 문자열 포함)이 들어 있습니다. 이는 http.IncomingMessage 객체의 일부입니다.
const http = require('http');
const server = http.createServer((req, res) => {
// URL과 HTTP 메서드 추출
const { url, method } = req;
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`You made a ${method} request to ${url}`);
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
url 모듈 활용
url 모듈은 URL 해석 및 파싱 유틸리티를 제공합니다.
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
// URL 파싱
const parsedUrl = url.parse(req.url, true);
// 각 부분 추출
const pathname = parsedUrl.pathname; // 쿼리 문자열 제외된 경로
const query = parsedUrl.query; // 객체 형태의 쿼리 문자열
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
pathname,
query,
fullUrl: req.url
}, null, 2));
});
server.listen(3000);
예시 요청:
GET /products?category=electronics&sort=price&page=2 HTTP/1.1
위 서버는 다음과 같이 응답합니다.
{
"pathname": "/products",
"query": {
"category": "electronics",
"sort": "price",
"page": "2"
},
"fullUrl": "/products?category=electronics&sort=price&page=2"
}
querystring 모듈 (고급 파싱)
const http = require('http');
const { URL } = require('url');
const querystring = require('querystring');
const server = http.createServer((req, res) => {
// 최신 URL API 사용 (Node.js 10+)
const baseURL = 'http://' + req.headers.host + '/';
const parsedUrl = new URL(req.url, baseURL);
// 쿼리 파라미터 객체화
const params = Object.fromEntries(parsedUrl.searchParams);
// 쿼리 문자열 생성 예시
const queryObj = {
name: 'John Doe',
age: 30,
interests: ['programming', 'music']
};
const queryStr = querystring.stringify(queryObj);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
path: parsedUrl.pathname,
params,
exampleQueryString: queryStr
}, null, 2));
});
server.listen(3000);
응답 예시:
{
"path": "/",
"params": {},
"exampleQueryString": "name=John%20Doe&age=30&interests=programming&interests=music"
}
주요 메서드 요약
url.parse(urlString, [parseQueryString], [slashesDenoteHost])→ URL 문자열을 객체로 파싱url.format(urlObject)→ URL 객체를 문자열로 포맷url.resolve(from, to)→ 기준 URL에 대한 상대 URL 해결new URL(input, [base])→ WHATWG URL API (신규 코드 권장)querystring.parse(str, [sep], [eq], [options])→ 쿼리 문자열을 객체로 파싱querystring.stringify(obj, [sep], [eq], [options])→ 객체를 쿼리 문자열로 변환
RESTful API와 HTTP 메서드
REST API는 리소스에 대한 다양한 작업을 수행하기 위해 GET, POST, PUT, DELETE 등 여러 HTTP 메서드를 사용합니다. 아래 예시는 Node.js HTTP 서버에서 메서드를 구분해 처리하는 방법을 보여줍니다.
const http = require('http');
const { URL } = require('url');
// 메모리 내 데이터 저장소(데모용)
let todos = [
{ id: 1, task: 'Learn Node.js', completed: false },
{ id: 2, task: 'Build an API', completed: false }
];
const server =