WEB

[웹소켓] 실시간 데이터 전송하기(feat.Java)

연신내고독한늑대 2025. 1. 20. 09:42

웹 애플리케이션에서 특정 상황에 따라 실시간으로 데이터를 클라이언트에 전달하고 싶을 때, **웹소켓(WebSocket)**을 활용하는 방법이 있습니다. 실시간 데이터 전송을 처리할 수 있는 다양한 방법들이 있지만, 저는 양방향 통신을 가능하게 해주는 웹소켓을 사용하기로 결정했습니다.

■ HTTP와 WebSocket의 차이점

HTTP의 한계:

HTTP는 클라이언트 → 서버 요청-응답 모델로 동작합니다. 클라이언트가 서버에 요청을 보내면 서버가 응답을 보내는 방식입니다. 이 구조는 단방향 통신이므로 서버는 클라이언트가 요청하지 않으면 데이터를 보낼 수 없습니다.

즉, 서버가 클라이언트에 데이터를 푸시(push)하는 방식은 지원되지 않습니다.

 

WebSocket: HTTP의 한계를 넘다

WebSocket양방향 통신을 가능하게 해주며, 한 번 연결되면 클라이언트와 서버가 실시간으로 데이터를 주고받을 수 있는 연결을 유지합니다. 이는 HTTP에서 발생하는 실시간 통신의 한계를 해결하기 위한 기술로, 서버에서 클라이언트로 실시간 데이터를 푸시할 수 있게 만들어졌습니다.

HTTP는 요청-응답 방식으로만 동작하는 반면, WebSocket은 양방향 실시간 통신을 지원하여, 서버가 클라이언트의 요청 없이도 데이터를 전송할 수 있습니다. 이 특성 덕분에 채팅 시스템, 실시간 알림, 게임 등과 같은 실시간 애플리케이션에서 WebSocket이 매우 유용하게 사용됩니다.

 

■ WebSocket의 기본 흐름

일반적으로 WebSocket 연결은 다음과 같은 흐름으로 이루어집니다:

  1. 클라이언트 → HTTP 요청: 클라이언트는 WebSocket 연결을 시작하기 위해 HTTP 요청을 보냅니다 (GET /ws).
  2. 서버 → WebSocket 연결: 서버는 HTTP 요청을 WebSocket 프로토콜로 업그레이드하여 연결을 수립합니다.
  3. WebSocket → 양방향 통신: WebSocket 연결이 수립되면 클라이언트와 서버는 실시간으로 데이터를 주고받을 수 있습니다.
  4. 서버 → WebSocket 메시지 → 클라이언트: 서버는 특정 클라이언트에게 데이터를 실시간으로 전송할 수 있습니다.

 

■ HTTP-Only 쿠키와 WebSocket에서 JWT 토큰 사용하기

저는 WebSocket 연결 시 클라이언트의 인증 정보를 WebSocket 세션으로 전달해야 했습니다(웹소켓에서는 http 정보를 담지 않는게 기본). 이때, **HTTP-Only 쿠키에 저장된 JWT(Json Web Token)**을 사용하여 클라이언트를 인증하는 방식으로 처리했습니다. 그런데 WebSocket 연결 시 HTTP 요청에서 받은 JWT 토큰을 WebSocket 세션으로 어떻게 전달할까요?

 

**HandshakeInterceptor**를 implements하여, WebSocket 연결 시 HTTP 요청에서 데이터를 추출하고 이를 WebSocket 세션에 전달하는 **CustomHandshakeInterceptor**를 만들면 됩니다. 이 과정을 통해, WebSocket 메시징에서 인증 정보를 활용할 수 있게 됩니다.

## CustomHandshakeInterceptor 코드

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import java.util.Map;

// HTTP 쿠키를 웹소켓 세션에 저장하는 과정
public class CustomHandshakeInterceptor implements HandshakeInterceptor {

    @Override
    public boolean beforeHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Map<String, Object> attributes
    ) {
        if (request instanceof ServletServerHttpRequest) {
            HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
            HttpSession session = servletRequest.getSession();
            // 쿠키 또는 기타 데이터를 WebSocket 세션으로 전달
            attributes.put("sessionId", session.getId());
            attributes.put("jwt-token", getJwtFromCookies(servletRequest));
        }
        return true;
    }

    @Override
    public void afterHandshake(
            ServerHttpRequest request,
            ServerHttpResponse response,
            WebSocketHandler wsHandler,
            Exception exception
    ) {
        // 핸드셰이크 후 처리
    }

    private String getJwtFromCookies(HttpServletRequest request) {
        if (request.getCookies() != null) {
            for (Cookie cookie : request.getCookies()) {
                if ("jwt-token".equals(cookie.getName())) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }
}

 

■ 결론: 왜 WebSocket인가?

HTTP의 단방향 통신 모델은 실시간 데이터 전송에 한계가 있었습니다. 이 한계를 극복하기 위해 WebSocket이 등장하여, 양방향 실시간 통신을 가능하게 했습니다. WebSocket을 사용하면 서버에서 클라이언트로 실시간 데이터를 푸시할 수 있으며, 이를 통해 채팅, 알림 시스템, 실시간 게임 등 다양한 애플리케이션에서 유용하게 활용할 수 있습니다.

**CustomHandshakeInterceptor**를 사용하면 WebSocket 연결 시 인증 정보를 세션에 전달할 수 있어, 실시간 메시징을 처리하는 데 중요한 역할을 합니다.