Spring/Spring

[Spring WebSockets] WebSockets

noahkim_ 2025. 5. 2. 12:55

1. WebSocket 소개

WebSocket 프로토콜 (RFC 6455)

  • 클라이언트와 서버 간에 하나의 TCP 연결 위에서 양방향(full-duplex) 통신 가능.
  • HTTP를 기반으로 동작하지만, HTTP와는 다른 프로토콜이다.
    • 80, 443 포트 사용
    • 기존 방화벽 규칙 재사용 가능.

 

참고사항

  • WebSocket 서버가 nginx 같은 프록시 서버 뒤에 있을 경우, 업그레이드 요청을 프록시가 제대로 전달하도록 설정 필요.
  • 클라우드 환경에서는 WebSocket 지원 여부를 클라우드 제공업체 문서에서 확인해야 함.

 

2. WebSocket API

설정

  • WebSocketConfigurer 오버라이딩

 

예제

더보기
@Configuration
public class WebsocketConfig implements WebSocketConfigurer {
    
    @Autowired
    private ChatMessageHandler chatMessageHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(chatMessageHandler, "/chat");
    }
}

 

전체 흐름

[Client] 
  ↓ (HTTP Upgrade 요청: ws://)
[HandshakeInterceptor]       <-- (Spring에서는 HandlerInterceptor 계열로 등록하는 HandshakeInterceptor)
  ↓
[DefaultHandshakeHandler]     <-- (handshake를 처리하고 실제 WebSocket 연결을 만듬)
  ↓
[WebSocketHandlerDecorator]   <-- (연결 이후부터 통신을 감싸서 부가기능 추가)
  ↓
[실제 WebSocketHandler]       <-- (너가 작성하는 실제 비즈니스 처리)
단계 설명
HandshakeInterceptor
(HandlerInterceptor 계열)
WebSocket 연결 핸드쉐이크 전 작업 등록 (토큰 인증, 세션 체크, 요청 헤더 검사)
- WebSocket 업그레이드 요청 전에 HTTP 요청을 가로챔
DefaultHandshakeHandler
WebSocket 프로토콜로 업그레이드를 실제로 수행
- RequestUpgradeStrategy: WAS마다 WebSocket을 어떻게 업그레이드 할지를 정하는 전략
- 클라이언트 세션 ID 부여
WebSocketHandlerDecorator 연결이 완료된 이후 통신 과정을 감싸면서 부가기능 추가 (로깅, 에러처리, 커스텀 로직 등)
- ExceptionWebSocketHandlerDecorator: 에러 처리 (WebSocket 에러 시, 1011로 연결 종료)
WebSocketHandler
WebSocket 연결 이후, 수신 프레임을 처리하는 핸들러
- 프레임 유형에 맞게 상속해서 구현하는 방식 (TextWebSocketHandler, BinaryWebSocketHandler)

 

예제) HandshakeInterceptor

더보기
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(chatMessageHandler, "/chat")
            .addInterceptors(new HttpSessionHandshakeInterceptor()); // HTTP attribute를 Websocket 세션에 전달하는 목적으로 사용됨
}

 

예제) DefaultHandshakeHandler

더보기
@Bean
public DefaultHandshakeHandler handshakeHandler() {
    // Tomcat을 위한 RequestUpgradeStrategy 설정
    RequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
    return new DefaultHandshakeHandler(strategy);
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myHandler(), "/ws")
            .setHandshakeHandler(handshakeHandler());  // 여기 연결
}

 

예제) WebSocketHandlerDecorator

더보기
public class LoggingWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
    public LoggingWebSocketHandlerDecorator(WebSocketHandler delegate) {
        super(delegate);
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("WebSocket 연결 완료: " + session.getId());
        super.afterConnectionEstablished(session);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("WebSocket 에러 발생: " + exception.getMessage());
        super.handleTransportError(session, exception);
    }
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(new LoggingWebSocketHandlerDecorator(chatMessageHandler), "/chat")
}

 

예제) WebSocketHandler

더보기
@Component
public class ChatMessageHandler extends TextWebSocketHandler {
    
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("chat message received");
        System.out.println("payload: " + message.getPayload());
    }
}

 

3. 부가 기능

배포

  • Jakarta WebSocket (JSR-356)은 기본적으로 클래스패스 스캔 또는 초기화 API 등록 방식으로 WebSocket 엔드포인트를 배포.
  • DispatcherServlet처럼 모든 HTTP를 하나로 통합할 수 없음 (인터셉터, URL 패턴 등)
  • Spring은 이를 해결하기 위해 WAS별 RequestUpgradeStrategy를 제공
 
Jakarta WebSocket (@ServerEndpoint)
Spring MVC (@RestController)
요청 수신 서버(WAS)가 직접 받음
DispatcherServlet이 다 받음
등록 방식 어노테이션 스캔 or 직접 등록
빈 등록 + RequestMapping
확장성 제한적 (필터 체인 끼우기 어렵다)
매우 유연 (필터/인터셉터 쉽게 추가)
에러 처리 엔드포인트 단위
전역 예외처리(ControllerAdvice 등) 가능
라이프사이클 WAS 관리
Spring 컨테이너 관리

 

Cross-Oriign 허용

예제

더보기
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(chatMessageHandler, "/chat")
            .addInterceptors(new HttpSessionHandshakeInterceptor())
            .setAllowedOrigins("*");
}

 

옵션

  • 메시지 버퍼 크기, idle timeout 등 조정 가능

 

예제

더보기
@Bean
public ServletServerContainerFactoryBean servletServerContainerFactoryBean() {
    ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
    container.setMaxTextMessageBufferSize(1024 * 8);
    container.setMaxBinaryMessageBufferSize(1024 * 8);
    container.setMaxSessionIdleTimeout((1000L * 60 * 10));

    return container;
}

 

출처

'Spring > Spring' 카테고리의 다른 글

[Spring WebSockets] 2-3. STOMP: 부가 기능  (1) 2025.05.04
[Spring WebSockets] 2-1. STOMP: 주요 내용  (0) 2025.05.03
[Spring][AOP] 3. Advisor API  (0) 2025.04.09
[Spring][AOP] 2. Pointcut API  (1) 2025.04.09
[Spring][AOP] 1. Advice API  (0) 2025.04.09