HTTP 통신 기법 - 폴링(Polling) 이해와 구현

HTTP 통신 기법: 폴링(Polling) 이해와 구현

Polling
Polling

HTTP는 본질적으로 비연결성(stateless, connectionless)을 가진 프로토콜입니다.
즉, 클라이언트가 요청을 보내고 서버가 응답을 반환하면 연결은 곧바로 끊어집니다.

이 특성은 많은 웹 애플리케이션에서 문제가 되지 않지만,
실시간성이 요구되는 서비스—대표적으로 채팅 애플리케이션—에서는 곤란한 제약이 됩니다.
사용자가 메시지를 주고받을 때는 서버와 지속적으로 연결이 유지되어야 하기 때문입니다.

이번 포스트에서는 이 한계를 극복하기 위한 가장 단순한 기법인 폴링(Polling)을 살펴보고,
직접 서버와 클라이언트 구현 예제를 만들어보겠습니다.


1. 왜 폴링이 필요한가?

실시간 통신을 하려면 서버의 데이터를 계속 확인해야 합니다.
하지만 HTTP의 비연결성 때문에 한 번의 요청으로는 지속적인 확인이 불가능합니다.

이를 극복하는 가장 단순한 방법은 주기적으로 서버에 요청을 보내는 것입니다.

마치 버스가 올 때까지 계속 정류장에서 “지금 버스 왔나요?” 하고 묻는 것과 같습니다. 버스가 오지 않았더라도 물어보는 행위는 반복됩니다.

이 단순한 방식이 바로 폴링(Polling)입니다.


2. 폴링의 동작 원리

폴링은 다음과 같은 흐름으로 동작합니다:

  1. 클라이언트는 일정 주기마다 서버에 HTTP 요청을 보냅니다.
  2. 서버는 새로운 데이터가 있다면 응답 본문에 전달합니다.
  3. 데이터가 없다면 204 No Content와 같은 상태 코드를 반환합니다.
  4. 클라이언트는 일정 시간 대기 후 다시 요청을 반복합니다.

즉, 클라이언트는 “서버의 데이터를 당겨온다(Pull)”는 개념입니다.


3. 폴링 서버 구현하기

Node.js http 모듈을 사용해 간단한 채팅 서버를 만들어보겠습니다.

메시지 객체 정의

메시지 본문(text)생성 시각(timestamp)을 함께 저장해, 단순 문자열이 아닌 구조화된 데이터로 관리합니다.
toString() 메서드를 통해 이 객체를 JSON 문자열로 직렬화하여 클라이언트-서버 간 전송에 활용할 수 있습니다.

class Message {
  constructor(text) {
    this.text = text;
    this.timestamp = Date.now();
  }

  toString() {
    return JSON.stringify({
      text: this.text,
      timestamp: this.timestamp,
    });
  }
}js

서버 구성

HTTP 서버를 열고 /poll로는 신규 메시지 조회, /update로는 메시지 등록을 처리하도록 구성했습니다.

라우팅에 따라 적절한 핸들러를 실행하며, 없는 경로 요청에는 404를 반환합니다.

const http = require('http');
let message = null;

// 신규 메시지 조회
const poll = (req, res) => {
  if (!message) {
    res.statusCode = 204; // No Content
    res.end();
    return;
  }
  res.setHeader('Content-Type', 'application/json');
  res.end(`${message}`);
  message = null;
};

// 메시지 등록
const update = (req, res) => {
  let body = '';
  req.on('data', (chunk) => (body += chunk.toString()));
  req.on('end', () => {
    const { text } = JSON.parse(body);
    if (!text) {
      res.statusCode = 400;
      res.end(JSON.stringify({ error: 'text 필드를 채워주세요' }));
      return;
    }
    message = new Message(text);
    res.end(`${message}`);
  });
};

// 라우팅
const handler = (req, res) => {
  const { pathname } = new URL(req.url, `http://${req.headers.host}`);
  if (pathname === '/poll') return poll(req, res);
  if (pathname === '/update') return update(req, res);
  res.statusCode = 404;
  res.end('Not Found');
};

http.createServer(handler).listen(8080, () => {
  console.log('server running ::8080');
});js

4. 요청 흐름 살펴보기

1) 메시지가 없을 때

curl http://localhost:8080/poll -vbash

응답:

< HTTP/1.1 204 No Content

2) 메시지 등록하기

curl http://localhost:8080/update \
  -H "Content-Type: application/json" \
  -d '{"text":"hello"}' -vbash

응답:

< HTTP/1.1 200 OK
{"text":"hello","timestamp":...}

3) 메시지 조회하기

curl http://localhost:8080/poll -vbash

응답:

< HTTP/1.1 200 OK
{"text":"hello","timestamp":...}

다시 요청을 보내면 204가 반환됩니다. 이미 메시지를 소비했기 때문입니다.


5. 클라이언트 구현

브라우저에서 5초마다 /poll 요청을 보내도록 구성합니다.

const pollServer = async () => {
  const INTERVAL_MS = 5_000;
  const response = await fetch('/poll');

  if (response.status === 204) {
    setTimeout(pollServer, INTERVAL_MS);
    return;
  }

  const message = await response.json();
  render(message);
  setTimeout(pollServer, INTERVAL_MS);
};

const render = (message) => {
  const div = document.createElement('div');
  div.textContent = `${message.text} (${new Date(
    message.timestamp
  ).toLocaleTimeString()})`;
  document.body.appendChild(div);
};

document.addEventListener('DOMContentLoaded', pollServer);js

일단 네트워크 탭을 보면 계속 요청을 5초마다 보내고 있지만, 실제로 데이터들이 화면에 표시되어있지는 않다.

이는 우리가 당연히 서버에서 클라이언트에게 데이터를 보내지 않았기 때문이다.

curl http://localhost:8080/update \
  -H "Content-Type: application/json" \
  -d '{"text":"hello"}' -vbash

이제 서버에 메시지를 업데이트하면 클라이언트 화면에 새로운 메시지가 표시됩니다.

클라이언트 폴링
클라이언트 폴링


6. 폴링의 장단점

장점

  • 구현이 단순하다
  • 특별한 프로토콜이나 라이브러리 없이 HTTP로 가능하다
  • 빠르게 테스트하거나 프로토타입을 만들 때 유용하다

단점

  • 비효율적: 데이터가 없어도 주기적으로 요청을 발생
  • 네트워크 비용 증가: 불필요한 요청이 많음
  • 실시간성 한계: 요청 주기에 따라 지연 발생
  • 서버 부하: 클라이언트 수가 많으면 서버에 부담

7. 비유로 이해하기

폴링(Polling)은 카톡에서 계속 “새 메시지 있어?”라고 물어보는 것과 같습니다.
메시지가 없어도 주기적으로 확인하기 때문에 데이터(요금)가 낭비되고,
서버 입장에서도 불필요한 요청이 쌓여 부담이 커집니다.

구현은 간단하지만 효율이 떨어지는 방식이므로,
보통은 푸시 알림, WebSocket, 서버 푸시 같은 대안이 더 선호됩니다.


8. 마무리 및 다음 이야기

폴링은 HTTP의 비연결성을 극복하기 위한 가장 단순한 기법입니다.
그러나 실시간성이 중요한 시스템에서는 효율적이지 못합니다.

그래서 다음 포스트에서는 폴링보다 진보된 방식인 롱 폴링(Long Polling)을 살펴보겠습니다.
또한 서버 푸시(Server-Sent Events)양방향 통신(WebSocket)까지 다루며, 실시간 통신 기술의 발전 과정을 정리해 보겠습니다.