1. HTTP 서버 구성 순서
Node.js에서 HTTP 서버를 구축하는 과정은 비교적 간단하다.
기본적으로 http 모듈을 사용하여 서버를 생성하고 구성한다.
서버 구성은 크게 http 모듈 불러오기, 서버 인스턴스 생성, 포트 바인딩의 세 단계로 이루어진다.
이 과정을 통해 클라이언트의 요청을 처리하고 응답을 반환하는 기본적인 웹 서버를 구축할 수 있다.
2. HTTP 서버 구성요소
2.1. createServer
HTTP 서버 인스턴스를 생성한다.
이 메서드는 요청 핸들러 함수를 인자로 받으며, 이 핸들러 함수는 클라이언트의 모든 HTTP 요청을 처리한다.
요청 핸들러 함수는 두 개의 객체를 매개변수로 받는다.
- req (request): 클라이언트의 요청 정보를 담고 있는 객체
- res (response): 클라이언트에게 응답을 보내기 위한 객체
ex)
const http = require('http');
const server = http.createServer((req, res) => {
// 요청 처리 및 응답 생성 로직
});
createServer는 http.Server 클래스의 인스턴스를 반환하며, 이 인스턴스는 EventEmitter를 상속받는다.
따라서 이벤트 기반으로 서버를 관리할 수 있다.
2.2. listen
listen 메서드는 서버가 특정 포트에서 들어오는 연결을 수신하도록 설정한다.
기본적인 형태로 포트 번호와 콜백 함수를 인자로 받는다.
ex)
server.listen(port, [hostname], [backlog], [callback]);
- port: 연결을 수신할 포트 번호
- hostname (선택): 연결을 수신할 호스트 이름 (기본값: '0.0.0.0')
- backlog (선택): 연결 대기열의 최대 크기 (기본값: 511)
- callback (선택): 서버가 시작될 때 호출되는 함수
콜백 함수 대신 이벤트 리스너를 사용할 수도 있다.
server.on('listening', () => {
console.log('서버가 시작되었습니다.');
});
server.on('error', (error) => {
console.error('서버 오류 발생:', error);
});
server.listen(3000);
2.3. end
응답 데이터 전송을 완료하고 연결을 종료한다.
이 메서드는 선택적으로 마지막 데이터 청크를 인자로 받을 수 있다.
ex)
res.end([data], [encoding]);
- data (선택): 마지막으로 전송할 데이터
- encoding (선택): 데이터의 인코딩 (기본값: 'utf8')
중요 사항:
- end 메서드는 모든 응답에서 반드시 호출되어야 한다.
- end를 호출하지 않으면 클라이언트는 응답이 완료될 때까지 계속 대기하게 된다.
- end 호출 후에는 더 이상 데이터를 전송할 수 없다.
3. HTTP 서버 예시
const http = require('http'); // http 객체 생성
let count = 0;
const server = http.createServer((req, res) => { // 서버 객체 생성
log(count++); // count 증가
res.statusCode = 200; // 상태코드 200
res.statusMessage = 'OK'; // 상태메시지 OK
res.setHeader('Content-Type', 'text/plain'); // 응답헤더 설정
res.write('Hello\n'); // 응답 본문에 Hello 추가
setTimeout(() => { res.end('World\n'); }, 1000); // 응답 본문에 World 추가 후 응답 종료
});
function log(count){
console.log(count);
}
server.listen(4000, () => {console.log('Hello World!')});
3.1. 각 부분 상세 설명
1) http 모듈 불러오기
const http = require('http');
Node.js의 코어 모듈인 http를 불러와 http 변수에 할당한다.
변수 이름은 다르게 지정해도 되지만, 관례적으로 http로 사용한다.
2) 서버 인스턴스 생성
const server = http.createServer((req, res) => { ... });
createServer 메서드를 호출하여 HTTP 서버 인스턴스를 생성한다.
인자로 전달된 콜백 함수는 클라이언트의 요청이 들어올 때마다 실행된다.
매개변수:
- req: 요청 객체로, 클라이언트의 요청 정보를 포함
- res: 응답 객체로, 클라이언트에게 응답을 보내는 데 사용
3) 응답 상태 설정
res.statusCode = 200;
res.statusMessage = 'OK';
HTTP 응답 상태 코드와 메시지를 설정한다.
- 200: 성공적인 요청을 의미
- 'OK': 상태 코드에 해당하는 표준 메시지
4) 응답 헤더 설정
res.setHeader('Content-Type', 'text/plain');
응답 헤더에 콘텐츠 타입을 설정한다.
'text/plain'은 응답 본문이 일반 텍스트임을 나타낸다.
다른 일반적인 콘텐츠 타입으로는 'text/html', 'application/json' 등이 있다.
5) 응답 데이터 작성
res.write('Hello\n');
write 메서드를 사용하여 응답 본문에 데이터를 추가한다.
이 메서드는 여러 번 호출하여 데이터를 스트리밍할 수 있다.
6) 응답 종료
setTimeout(() => { res.end('World\n'); }, 1000);
1초 후에 end 메서드를 호출하여 응답을 종료한다.
end의 인자로 전달된 'World\n'는 응답의 마지막 데이터로 전송된다.
end 호출 후에는 더 이상 데이터를 전송할 수 없으며, 연결이 종료된다.
7) 서버 시작
server.listen(4000, () => {console.log('Hello World!')});
서버가 4000번 포트에서 연결을 수신하도록 설정한다.
호스트 이름이 생략되었으므로 기본값인 '0.0.0.0'(모든 네트워크 인터페이스)이 사용된다.
콜백 함수는 서버가 시작되면 실행되어 'Hello World!'를 콘솔에 출력한다.
4. 주의사항
1) 항상 응답 종료하기
모든 요청 처리 경로에서 res.end()가 호출되도록 해야 한다.
그렇지 않으면 클라이언트는 계속 응답을 기다리다가 시간 초과될 수 있다.
2) 오류 처리
오류가 발생할 때 반드시 응답 콜백 함수를 작성해야 한다.
만약 오류가 발생했을 때 실행할 응답이 없다면 서버는 응답이 오길 계속 기다리다가 timeout 에러가 발생한다.
ex)
const server = http.createServer((req, res) => {
try {
// 요청 처리 로직
res.end('성공적으로 처리되었습니다.');
} catch (error) {
// 오류 처리 로직
console.error('오류 발생:', error);
res.statusCode = 500;
res.end('서버 내부 오류가 발생했습니다.');
}
});