프로젝트에 실시간 알림 기능이 필요해지면서, 어떤 방식으로 구현할지 여러 방법을 비교해봤습니다. 대표적으로 Polling, WebSocket, 그리고 Server-Sent Events(SSE)가 있었는데, 저희 서비스에는 SSE가 가장 적합하다고 판단했습니다.
우선, 알림 기능은 서버에서 클라이언트로 일방적으로 데이터를 전달하는 구조였기 때문에, 굳이 양방향 통신이 가능한 WebSocket까지는 필요하지 않았습니다. WebSocket은 실시간성과 유연성이 뛰어나지만, 그만큼 구현과 유지 관리가 복잡해지는 단점이 있습니다.
반면에 SSE는 HTTP 기반으로 작동해 구현이 간단하고, 브라우저에서도 EventSource
만으로 쉽게 사용할 수 있어 프론트엔드 측에서도 다루기 수월했습니다. 또한 Polling보다 리소스 소모가 적고 실시간 반응 속도도 뛰어나 SSE를 선택했습니다.
EventSourcePolyfill
을 사용한 SSE 연결 구현저희 프로젝트는 로그인 후 사용하는 서비스이기 때문에, 사용자마다 개별 알림을 받아야 하는 구조입니다.즉, SSE 연결 시 각 사용자의 인증 토큰(JWT)을 함께 전달해줘야 했습니다.
하지만 기본 EventSource
객체는 커스텀 헤더를 설정할 수 없다는 제한이 있어, Authorization
헤더에 JWT를 담는 방식은 사용할 수 없었습니다.
이 문제를 해결하기 위해 event-source-polyfill
라이브러리를 도입했습니다.
import { EventSourcePolyfill } from 'event-source-polyfill';
const eventSource = new EventSourcePolyfill(
`${import.meta.env.VITE_API_URL}/api/alert/connect`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
accessToken
의 변화에 맞춰 SSE 연결을 유지하기 위해 useEffect
를 활용했습니다. 의존성 배열에 accessToken
을 추가하여, 토큰이 갱신될 때마다 기존 연결을 해제하고 새로운 토큰으로 다시 연결을 하도록 설계했습니다.
이 방식은 기존 연결을 먼저 끊고 새로운 토큰으로 재연결을 시도하므로, 만료된 토큰으로 인한 인증 오류나 불필요한 연결 시도를 막고 항상 유효한 연결만 유지합니다.
![]() | ![]() |
---|
SSE를 적용한 결과, 다음과 같은 실시간 흐름을 구현할 수 있었습니다: