본문 바로가기

항해 99/Spring

WebSocket - SockJS

SockJS 란?

SockJS의 목표는 애플리케이션이 우선적으로 WebSocket API를 사용하도록 하지만, 사용할 수 없는 경우에는 런타임 시점에 코드 변경없이 WebSocket 이외의 대안으로 대체하도록 하는 것

 

특징

SockJS는 브라우저에서 사용하도록 설계가 되었기 때문에, 다양한 브라우저와 버전을 지원하고 있음

 

SockJS는 WebSocket, HTTP Streaming, HTTP Long Polling 등의 크게 세 가지 전송 방법(Transports)을 지원하고 있는데, 이 외에도 다양한 방식을 제공함

 

WebSocket Emulation 과정

SockJS는 서버로부터 기본 정보를 획득하기 위해서 GET / info 요청을 보내며 시작함

클라이언트가 서버에게 GET / info 요청을 보냄으로써, 서버가 WebSocket을 지원하는 지와 전송 과정에서 Cookies 지원이 필요한지 여부, CORS를 위한 Origin 정보 등의 정보를 응답으로 전달받음

 

서버가 응답한 메시지를 토대로 앞으로 통신에 사용할 프로토콜을 아래와 같은 방식으로 결정하고 요청을 보냄

  • WebSocket 사용 가능하다면, WebSocket 사용
  • WebSocket 사용 불가능하면
    • Options의 Transports 항목에 HTTP streaming 설정이 존재한다면, HTTP streaming 사용
    • Options의 Transports 항목에 HTTP streaming 설정이 없고 HTTP Long Polling 존재하면 HTTP Long Polling 사용
const sock = new SockJS('http://localhost:8080/test', null, {transports: ["websocket", "xhr-streaming", "xhr-polling"]});

 

Transports Request URL 형식

모든 Transports Request 요청의 URL 형식은 아래와 같음

http://host:port/myApplication/myEndpoint/{server-id}/{session-id}/{transport}
  • server-id : 클러스터 환경에서 요청을 라우팅하는데 유용하게 사용된다
  • session-id :  SockJS 세션에 속하는 HTTP 요청을 연관시킴
  • transport : 전송 타입(websocket, xhr-streaming, xhr-polling)

Transports Type

websocket 타입의 전송 방식은 Websocket HandShake를 하기 위해서 오직 하나의 HTTP 요청만 필요하고, 이후 모든 메시지는 해당 소켓에서 교환한다

 

xhr-streaming 타입의 경우에는 장기 실행 요청을 유지하여 서버에서 클라이언트로 전달하기 위한 메시지를 응답으로 전달받음

 

이후, 클라이언트에서 서버로 새로운 요청을 보내야 할 경우에는 기존의 커넥션을 종료하고 새로운 HTTP POST 요청을 보내 커넥션을 유지함

 

xhr-polling 타입 경우에는 서버에서 클라이언트로 응답 메시지가 전달이 될 때마다 기존의 커넥션을 종료하고 새로운 요청을 보내여 커넥션을 생성

 

메시지 형식

추가적으로, SockJS는 Message Frame 크기를 최소화하기 위해 노력함(open frame의 경우에는 첫 글자인 o를 전송함)

 

또한, Message Frame의 경우에는 다음과 같은 형태로 전달받음

a["message1", "message2"]

 

커넥션 유지 여부를 확인하는 Heartbeat Frame 경우에는 h로 보냄

 

마지막으로, 커넥션 종료를 의미하는 Close Frame은 c["message"] 형식으로 보냄

 

SockJS 사용

SockJS는 아래와 같이 설정할 수 있음

 

스프링에서 제공하는 WebSocket API와 SockJS는 Spring MVC에 독립적이지만, 관련된 Configuration 설정들은 DispatcherServlet에 포함되어야 함

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
		webSocketHandlerRegistry
			.addHandler(webSocketHandler(), "/test")
			.withSockJS();
	}

	@Bean
	public WebSocketHandler webSocketHandler() {
		return new Handler();
	}
}

 

클라이언트 측에서는 sockjs-client 라이브러리를 사용하는데, 서버와 통신하여 브라우저에 따른 최적의 전송 옵션(타입)을 선택함

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        .message {
            margin: 5em;
            color: olive;
            border: solid 2px #D2691E;
            -webkit-transition: 0.5s; transition: 0.5s;
            width: 50%;
            padding: 10px 20px;
            box-sizing: border-box;
        }
        .messages {
            margin: 5em;
        }
        .send-btn {
            background-color: #F4FEE2;
            padding: 10px 20px;
        }
        li {
            list-style-type: none;
            margin: 1em;
            text-align: center;
            font-size: 2em;
        }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
</head>
<body>
    <div>
        <input type="text" class="message"/>
        <button onClick='send()' class="send-btn">보내기</button>
    </div>
    <div class="messages">
        <div id="messages"></div>
    </div>
</body>
    <script>
        let sock;
        document.addEventListener("DOMContentLoaded", function() {
            // ["websocket", "xhr-streaming", "xhr-polling"]
            sock = new SockJS('http://localhost:8080/test', null, {transports: ["websocket", "xhr-streaming", "xhr-polling"]});
            sock.onopen = function() {
                console.log('Connected!!');
            };

            sock.onmessage = function(event) {
                const messages = document.querySelector("#messages");
                const message = document.createElement("li");
                message.innerText = event.data;
                messages.appendChild(message)
            };

            sock.onclose = function() {
                console.log('close');
            };
        });

        function send() {
            const message = document.querySelector(".message");
            sock.send(message.value);
            message.value = '';
        }
    </script>
</html>

 

IE 8, 9 호환성

WebSocket은 IE 8, 9 버전을 지원하고 있지 않음, SockJS는 HTTP Streaming 또는 HTTP LongPolling Transports 타입으로 전환되어 호환이 가능함

 

SockJS 클라이언트는 Microsoft의 XDomainRequest(xdr) 이용해서 HTTP Streaming을 지원함(10부터 XMLHttpRequest(xhr) 사용을 권장하여 XDomainRequest 를 제거)

 

XDomainRequest(xdr), XMLHttpRequest(xhr)는 모두 CORS를 지원하기 위한 도구이다.

 

XDomainRequest는 CORS 도구로서 잘 동작하지만, Cookies 전송을 지원하지 않음, 쿠키는 종종 Java 애플리케이션에서 필수적이지만, SockJS 클라이언트는 여러 유형의 서버와 함께 사용할 수 있어 큰 문제는 아님

 

서버 측의 Cookies 필요 여부에 따라 HTTP Streaming, HTTP Long Polling에서 사용하는 기술이 달라짐

  • Cookies 사용 불가 시 XDomainRequest(xdr)가 사용됨
  • Cookies 사용 가능 시 iframe 기반의 기술이 사용됨

SockJS 클라이언트가 첫 번째로 요청한 GET / info에 대한 응답 메시지에는 클라이언트가 Transports 타입을 선택하는데 영향을 미치는 요소들이 포함되어 있음

 

서버가 Cookies 정보가 필요한 지 등의 정보를 클라이언트에게 응답 메시지로 전달한다.

 

cookies-needed 항목은 스프링에서 setSessionCookieneeded(boolean) 메서드로 제어 가능하며, 아래와 같이 설정 가능

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
		webSocketHandlerRegistry
			.addHandler(webSocketHandler(), "/test")
			.withSockJS()
			.setSessionCookieNeeded(false);
	}

	...
}
  • setSessionCookieNeeded 의 default 값은 true임(Java 애플리케이션에서 JSESSIONID 쿠키를 많이 사용하기 때문)

 

서버에서 쿠키가 필요하지 않을 경우 SockJS 클라이언트는 IE 8, 9 버전에서 XDomainRequest를 사용함

 

iframe 기반의 Transports를 사용하는 경우에는 브라우저가 [X-Frame-Options](https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/X-Frame-Options) 응답 헤더에 지정한 DENY, SAMEORIGIN, ALLOW-FROM <origin> 페이지들에 대해서만 iframe을 렌더링하도록 방지할 수 있음

  • DENY는 모든 iframe에서 사용될 수 없음
  • SAMEORIGIN은 동일한 출처, 즉 같은 도메인인 경우에만 허용
  • ALLOW-FROM<origin>는 지정한 도메인 URI에 대해서만 허용

※ X-Frame-Options 응답 헤더는 해당 페이지를 <frame>, <iframe>, <object>에서 렌더링할 수 있는 지 여부를 의미한다.

 

iframe 기반의 Transports를 사용하고 X-Frame-Options 응답 헤더를 포함하려면, 반드시 SAMEORIGIN 이거나 ALLOW-FROM<origin>에 SockJS 클라이언트 도메인을 지정해야만 한다

  • iframe로부터 로드되기 위해서는 스프링 서버의 SockJS가 클라이언트의 위치를 알고 있어야 함

스프링은 SAMEORIGIN을 지원하기 위해서 SockJS-Client 접근 경로를 설정할 수 있도록 아래와 같이 제공함

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
		webSocketHandlerRegistry
			.addHandler(webSocketHandler(), "/test")
			.withSockJS()
			.setClientLibraryUrl("http://localhost:8080/myApplication/js/sockjs-client.js")
	}

	@Bean
	public WebSocketHandler webSocketHandler() {
		return new Handler();
	}
}

 

Heartbeat

SockJS 프로토콜은 서버가 주기적으로 Heartbeat Message를 전송해, 프록시가 커넥션이 끊겼다고 판단하지 않도록 함

 

스프링 SockJS Configuration은 HeartbeatTime을 사용자가 지정할 수 있도록 setHeartbeatTime(long) 메서드를 제공하는데, HeatbeatTime의 시작은 마지막 메시지가 전송 된 이후부터 카운트 됨(default 25초)

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
		webSocketHandlerRegistry
			.addHandler(webSocketHandler(), "/test")
			.withSockJS()
			.setHeartbeatTime(30)
	}

	@Bean
	public WebSocketHandler webSocketHandler() {
		return new Handler();
	}
}

 

스프링 SockJS는 Heartbeat Tasks를 스케줄링할 수 있도록 TaskScheduler를 설정할 수도 있음, TaskScheduler는 기본적으로 사용 가능한 프로세서 수만큼 생성되어 Thread Pool에 백업됨

  • STOMP를 사용해 Heartbeat를 주고 받을 경우에는 SockJS Heartbeat 설정은 비활성화

Client Disconnects

SockJS Transports 타입인 HTTP Streaming과 HTTP Long Polling은 일반 요청보다 더 긴 커넥션을 요구함

 

이러한 요구 사항은 서블릿 컨테이너에서 Servlet 3 asynchronous 지원을 통해 수행 됨, 구체적으로 Servlet 3 asynchronous는 Servlet Container Thread가 종료되고도 요청을 처리하며 다른 스레드가 지속적으로 응답에 Write할 수 있도록 지원함

 

여기서 문제점은 Servlet API가 갑자기 사라진 클라이언트에 대한 알림을 제공하지 않는다는 것임(Servlet Container는 응답에 Write를 시도하는 경우 예외를 발생시킴)

 

스프링 SockJS는 서버 측에서 주기적으로 Heartbeat를 전송하기 때문에 클라이언트의 연결 여부를 일정 시간 안에 파악할 수 있음

 

SockJS와 CORS

Cross-Origin Request(CORS)를 허용한다면, SockJS 프로토콜은 HTTP Streaming, HTTP Long Polling 과정에서 해당 CORS를 사용함

 

스프링은 응답 헤더에서 CORS 헤더를 발견되지 않는다면 SockJS CORS에서 설정한 정보를 기반으로 헤더를 추가함

 

Servlet Filter를 통해서 이미 CORS 설정한 경우에는 스프링의 SockJsService에서의 CROS 설정은 건너 뜀,  각 핸들러에서는 setSupressCors(boolean) 메서드를 이용해서 SockJsService를 통한 CORS 헤더 추가 여부를 설정할 수 있음

 

SockJsService에서 CORS 헤더를 추가하도록 설정하고 싶은 경우 SockJS Endpoint의 Prefix에 대해서는 Servlet Filter를 제외하도록 설정함

 

SockJS CORS 헤더에 필요한 값

  • Access-Control-Allow-Origin는 Origin 요청 헤더의 값으로 초기화 됨
  • Access-Control-Allow-Credentials는 항상 True로 설정됨
  • Access-Control-Request-Headers는 실제 요청이 만들어질 때 클라이언트가 보낼 수도 있는 HTTP headers를 서버에게 알리는 용도로, 브라우저가 preflight request를 보내는 경우에 사용됨. SockJS에서는 Request와 동일한 헤더로 설정한다.
  • Access-Control-Allow-Methods는 서버가 지원하는 Transports 타입의 HTTP METHOD를 설정함
  • Access-Control-Max-Age는 preflight request 결과를 얼마나 캐시할 지를 나타내고, 31536000(1년)으로 설정됨

 

SockJS 설정

SockJS는 서버 측에서 HTTP Streaming에서 전송하는 메시지의 크기, 클라이언트가 연결이 끊긴 것으로 간주하는 시간 등의 설정을 WebSocketConfigurer의 SockJsServiceRegistration을 통해서 할 수 있음

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
		webSocketHandlerRegistry
			.addHandler(webSocketHandler(), "/test")
			.withSockJS()
			.setStreamBytesLimit(512 * 1024)
			.setHttpMessageCacheSize(1000)
			.setDisconnectDelay(30 * 1000)
	}

	@Bean
	public WebSocketHandler webSocketHandler() {
		return new Handler();
	}
}
  • StreamBytesLimit는 단일 HTTP 스트리밍 요청을 통해 전송될 수 있는 최소 바이트 수를 의미함(Default 128 * 1024)
  • HttpMessageCacheSize는 클라이언트의 다음 HTTP 폴링 요청을 기다리는 동안 서버가 클라이언트로 전송하기 위해 메시지들을 세션에 캐시할 수 있는 개수임(Default 100)
    • 다음 HTTP 폴링 요청에 대한 커넥션이 생성될 때까지 세션에 저장하고 있을 수 있는 메시지의 개수를 의미함
    • 모든 HTTP 기반의 Transports도 해당 속성을 사용함(HTTP Streaming도 사용)
  • DisconnectDelay는 클라이언트가 연결이 끊긴 것으로 간주되는 시간을 의미함(Default 5 * 1000)

SockJSClient

스프링은 브라우저 없이 SockJS Java Client를 이용해서 SockJS에 연결하는 기능을 제공함, 이런 기능은 두 서버간에 양방향 통신이 필요한 경우 유용하게 사용될 수 있음(테스팅하는 경우에도 요용하게 사용될 수 있음)

 

SockJS Java Client는 오직 websocket, xhr-streaming, xhr-polling Transports 타입만 제공하고, 나머지는 브라우저에서만 지원 됨

 

예제 : Transports 타입을 지정하고 SockJsClient를 이용해서 http://localhost:8080/test 서버와 연결

List<Transport> transports = new ArrayList<>();
transports.add(new WebsocketTransport(new StandardWebSocketClient()));
transports.add(new RestTemplateXhrTransport());

SockJsClient sockJsClient = new SockJsClient(transports);
sockJsClient.doHandshake(webSocketHandler(), "http://localhost:8080/test");

 

Transports 타입 등록 과정

  • 클라이언트 관점에서는 서버 연결에 사용되는 URL 외에 다른 차이점이 없기 때문에, XhrTransport는 xhr-streaming, xhr-polling 모두를 지원함
  • RestTemplateXhrTransport는 xhr-streaming와 xhr-polling 모두를 지원하는 XhrTransport 구현체임
  • RestTemplateXhrTransport는 내부적으로 HTTP Reqeust를 위해 스프링에서 제공하는 RestTemplate를 사용함
  • WebSocket 설정은 WebsocketTransport 객체를 통해 이루어지는데, JSR-356runtime에서 제공하는 StandardWebSocketClient를 사용하도록 지정함

HTTP Client 시뮬레이션 테스트

SockJsClient를 이용해서 여러 동시 사용자를 시뮬레이션하는 경우, HTTP Client(XHR transports)가 충분히 많은 커넥션과 스레드를 허용하도록 구성할 수 있음

 

Jetty 이용 예제

HttpClient httpClient = new HttpClient();
httpClient.setMaxConnectionsPerDestination(1000);
httpClient.setExecutor(new QueuedThreadPool(500));

 

SockJS 공식 문서 내용 분석 with GPT 4

패키지 : org.springframework.web.socket.config.annotation

클래스 SockJsServiceRegistration

java.lang.Object

  • org.springframework.web.socket.config.annotation.SockJsServiceRegistration

pubilc 클래스 SockJsService는 객체를 확장함

 

EnableWebSocket과 WebSocketConfigurer는 스프링에서 웹소켓을 설정하기 위한 인터페이스입니다. 이를 사용하여 웹소켓 엔드포인트를 등록하고 구성할 수 있습니다.

 

EnableWebSocket 애노테이션은 클래스에 적용하여 그 클래스에서 웹소켓을 사용할 수 있도록 합니다. 이는 스프링의 @Configuration 클래스에 주로 추가됩니다.

 

WebSocketConfigurer 인터페이스는 웹소켓 핸들러를 등록하는 메서드인 registerWebSocketHandlers를 포함합니다. 이 메서드를 구현하여 웹소켓 요청을 처리할 핸들러와, 해당 핸들러를 사용할 엔드포인트를 정의할 수 있습니다.

 

SockJS를 사용한 웹소켓 설정은 대체적으로 다음과 같은 방식으로 이루어집니다.

 

  1. @Configuration 클래스에 @EnableWebSocket 애노테이션을 추가합니다
  2. WebSocketConfigurer 인터페이스를 구현하는 클래스를 생성하고, registerWebSocketHandlers 메서드를 오버라이드하여 웹소켓 핸들러를 등록합니다.
  3. SockJS 옵션을 설정할 수 있도록 SockJsService 인스턴스를 생성하고, 이를 웹소켓 핸들러에 전달합니다.

여기서 SockJS 옵션은 클라이언트와 서버 같의 호환성을 높이기 위한 다양한 설정을 포함할 수 있습니다. 예를 들어, 폴링(polling) 인터벌이나 트랜스포트 옵션 등을 설정할 수 있습니다.

 

Constructor Summary

SockJsServiceRegistration()

 

Method Summary

 

  • getSockJsService( ) : 설정된 SockJsService를 반환
  • getTaskScheduler( ) : 설정된 TaskScheduler를 반환하는데, 이는 하트비트 메시지와 같은 작업을 예약하는 데 사용 됨
  • setAllowedOriginPatterns(String... originPatterns) 크로스 오리진 요청에 대해 허용된 Origin 헤더 패턴을 설정함
  • setAllowedOrigins(String... origins) : 위와 유사하지만 직접적으로 허용된 오리진을 설정함
  • setClientLibraryUrl(String clientLibraryUrl) : 브라우저에 의해 로드되어야 할 SockJS 클라이언트 라이브러리의 URL을 정의함
  • setDisconnectDelay(long disconnectDelay) : 연결이 끊긴 후 클라이언트가 연결이 끊긴 것으로 간주되기 전까지 대기하는 시간(밀리초)을 설정함
  • setHeartbeatTime(long heartbeatTime) : 연결을 유지하기 위해 하트비트 메시지를 보내는 간격(밀리초)을 설정함
  • setHttpMessageCacheSize(int httpMessageCacheSize) : HTTP 폴링 전송에 대해 캐시할 수 있는 서버-클라이언트 메시지 수를 구성함
  • setInterceptors(HandshakeInterceptor... interceptors) : 핸드셰이크 교환을 수정할 수 있는 인터셉터를 설정함
  • setMessageCodec(SockJsMessageCodec codec) : SockJS 메시지 인코딩 및 디코딩을 위한 코덱을 지정함
  • setSessionCookieNeeded(boolean sessionCookieNeeded) : SockJS가 올바르게 작동하기 위해 JSESSIONID 쿠키가 필요한지 여부를 나타냄
  • setStreamBytesLimit(int streamBytesLimit) : 스트리밍 전송에서 버퍼링된 데이터의 최대 크기를 결정
  • setSuppressCors(boolean suppressCors) : CORS 헤더의 자동 추가를 비활성화할 수 있음
  • setTaskScheduler(TaskScheduler scheduler) : SockJS 하트비트 메시지 예약을 위한 TaskScheduler를 지정함
  • setTransportHandlerOverrides(TransportHandler... handlers) : 기본 트랜스포트 핸들러를 재정의함
  • setTransportHandlers(TransportHandler... handlers) : SockJS의 다양한 트랜스포트 유형을 처리하기 위해 트랜스포트 핸들러를 등록
  • setWebSocketEnabled(boolean webSocketEnabled) : WebSocket 트랜스포트를 활성화할지 여부를 구성

이 메서드들은 스프링 애플리케이션 내에서 SockJS 서비스가 작동하는 방식을 세밀하게 조정하는데 사용되며, 크로스 오리진 요청 처리, 연결 유지 관리 전략, 메시지 인코딩 및 디코딩 등의 세부 사항을 다룸

각 메서드는 SockJS 서비스 동작의 특정 측면을 구성하는 설정자(setter)로, 다양한 브라우저와 네트워크 조건을 지원해야 하는 웹 애플리케이션에서 실시간 양방향 통신을 설정하는 데 필수적인 부분입니다.

 

Constructor Details

SockJsServiceRegistration

public SockJsServiceRegistration()

 

Method Details

setTaskScheduler

setTaskScheduler 메소드는 SockJS 하트비트를 예약하기 위해 사용할 TaskScheduler 인스턴스를 설정하는 데 사용됩니다. 이 하트비트는 클라이언트와 서버 간의 연결이 활성 상태임을 확인하는 데 사용되는 정기적인 신호입니다.

스프링 프레임워크에서 TaskScheduler는 예약된 작업을 실행하는 데 사용되며, 이 경우에는 정해진 간격으로 하트비트 메시지를 보내는 예약된 작업을 실행합니다. 웹소켓 연결에서 일반적으로 하트비트는 네트워크 타임아웃을 방지하고 연결이 여전히 살아있음을 양쪽 모두에게 알리는 데 사용됩니다.

 

ex)

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        registration.setTaskScheduler(heartbeatScheduler());
    }

    @Bean
    public TaskScheduler heartbeatScheduler() {
        // ThreadPoolTaskScheduler 생성 및 설정
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(1);
        scheduler.setThreadNamePrefix("sockjs-heartbeat-thread-");
        scheduler.initialize();
        return scheduler;
    }
}
  • ThreadPoolTaskScheduler를 생성하고 설정하여 하트비트를 보내기 위한 TaskScheduler로 사용
  • 하트비트 전송과 같은 주기적인 작업을 관리할 때 유용함
  • 설정된 TaskScheduler는 SockJsServiceRegistration에 등록되어 SockJS 서비스가 하트비트를 예약하고 전송하는 데 사용됨

 

setClientLibraryUrl

setClientLibraryUrl 메소드는 SockJS 서비스 구성에서 클라이언트 라이브러리를 로드할 URL을 설정하는 데 사용됩니다. 이 메소드는 특히 "eventsource", "htmlfile"과 같이 네이티브 크로스 도메인 통신을 지원하지 않는 트랜스포트를 사용할 때 중요합니다. 이러한 트랜스포트는 SockJS 서버와 동일한 도메인에서 실행될 수 있도록 보이지 않는 iframe 안에서 외부 도메인의 간단한 페이지를 로드해야 합니다.

사용 예시와 상황 설명
예를 들어, 클라이언트 사이드에서는 SockJS 라이브러리를 사용하여 웹소켓 연결을 시도합니다. 만약 웹소켓이 지원되지 않거나 사용할 수 없는 경우, SockJS는 다른 통신 방법(예: "eventsource", "htmlfile")으로 대체하여 통신합니다. 이때, 보이지 않는 iframe을 사용하여 동일한 출처 정책(Same-Origin Policy)을 우회할 수 있습니다.

기본 설정
기본적으로, setClientLibraryUrl은 "https://cdn.jsdelivr.net/sockjs/1.0.0/sockjs.min.js"로 설정되어 있습니다. 이는 CDN(Content Delivery Network)을 통해 SockJS 클라이언트 라이브러리를 제공합니다.

어플리케이션에 의해 제공되는 URL로 설정
개발자는 이 메소드를 사용하여 자신의 어플리케이션에 의해 제공되는 URL로 SockJS 클라이언트 라이브러리를 가리키도록 설정할 수 있습니다. 이 방법은 보안 요구사항이 더 엄격하거나, 특정 버전의 라이브러리를 사용해야 하는 경우에 유용합니다.

상대 URL 설정
개발자는 상대 URL을 지정하여 iframe 내에서 로드해야 하는 경우에 사용할 수 있습니다. 이 상대 URL은 iframe URL에 상대적이어야 하며, 예를 들어 SockJS 엔드포인트가 "/sockjs"로 매핑되어 있고 결과 iframe URL이 "/sockjs/iframe.html"이라면, SockJS 매핑 위의 위치로 올라가기 위해 "../../"로 시작하는 상대 URL이 필요합니다. 서블릿 매핑에 접두사가 있을 경우 더 많은 상위 경로 이동이 필요할 수 있습니다.

이러한 설정은 특히 SockJS의 다양한 트랜스포트 방식을 지원하고, 클라이언트 라이브러리의 로드 방식을 제어해야 할 때 중요합니다. 클라이언트 라이브러리 URL을 올바르게 설정하는 것은 SockJS 기반의 통신을 원활하게 하고, 클라이언트와 서버 간의 호환성을 유지하는 데 필수적입니다.

 

 

setStreamBytesLimit

setStreamBytesLimit 메소드는 HTTP 스트리밍 전송을 사용할 때, 단일 HTTP 스트리밍 요청을 통해 보낼 수 있는 바이트의 최소 양을 설정하는 데 사용됩니다. 이 값에 도달하면 현재의 HTTP 스트리밍 요청을 종료하고 클라이언트는 새 요청을 시작합니다.

스트리밍 전송은 클라이언트 측에서 응답을 저장하며, 전송된 메시지가 사용하는 메모리를 자동으로 해제하지 않습니다. 그렇기 때문에 연결을 주기적으로 재활용해야 할 필요가 있는데, 이 메소드는 그 연결 재활용의 기준이 되는 데이터 전송량을 설정합니다.

사용 이유
스트리밍 전송에서는 서버로부터 클라이언트로 지속적으로 데이터가 흐릅니다. 이 경우, 오랜 시간 동안 열린 상태를 유지하는 연결을 통해 많은 양의 데이터가 전송될 수 있으며, 이는 클라이언트의 메모리 사용량을 증가시킬 수 있습니다. 따라서, 설정된 바이트 한도에 도달하면 연결을 닫고 새 연결을 시작함으로써 메모리를 정리하고, 리소스 누수를 방지합니다.

기본값
기본적으로, setStreamBytesLimit의 값은 128K, 즉 128 * 1024 바이트로 설정됩니다. 이는 클라이언트가 새 연결을 시작하기 전에 하나의 HTTP 스트리밍 요청을 통해 전송할 수 있는 데이터의 양을 의미합니다.

특이 사항
이 값을 1로 설정하면 스트리밍을 사실상 비활성화하게 되어 스트리밍 전송이 폴링 전송처럼 동작하게 됩니다. 이는 서버로부터 주기적인 응답을 받는 대신에, 클라이언트가 새로운 연결을 지속적으로 열어야 한다는 것을 의미합니다. 이 방식은 네트워크 오버헤드가 더 크고 효율성이 떨어질 수 있으므로, 일반적으로 권장되지 않습니다.

스트리밍 전송을 적절히 관리함으로써, 클라이언트와 서버 간의 효율적인 실시간 통신을 지원하고 성능 및 안정성을 보장할 수 있습니다.

 

 

setSessionCookieNeeded

setSessionCookieNeeded 메소드는 SockJS 프로토콜에서 서버가 클라이언트의 초기 "/info" 요청에 응답할 때, 애플리케이션이 올바르게 기능하기 위해 JSESSIONID 쿠키의 사용이 필요한지를 나타내는 "cookie_needed" 부울 속성을 설정하는 데 사용됩니다. 예를 들어, 로드 밸런싱이나 Java 서블릿 컨테이너에서 HTTP 세션을 사용하는 경우에 JSESSIONID 쿠키가 필요할 수 있습니다.


쿠키의 필요성
JSESSIONID 쿠키는 클라이언트와 서버 간의 세션을 유지하는 데 일반적으로 사용됩니다. 이 쿠키는 클라이언트가 서버에 연속적인 요청을 보낼 때마다 해당 클라이언트의 세션을 서버가 식별할 수 있도록 해줍니다. 이는 로드 밸런싱이나 사용자 인증, 세션 정보의 저장 등에 필수적일 수 있습니다.

Internet Explorer 8과 9의 특수한 케이스
Internet Explorer 8과 9는 XDomainRequest라는 수정된 AJAX/XHR을 지원하는데, 이는 크로스 도메인 요청은 가능하지만 쿠키를 전송하지 않습니다. 따라서, 이러한 브라우저에서는 SockJS 클라이언트가 쿠키를 보낼 수 있는 "iframe-htmlfile" 전송 방식을 "xdr-streaming"보다 선호합니다.

기본값 설정
기본적으로 이 값은 "true"로 설정되어 있어, 쿠키(특히 JSESSIONID 쿠키)를 지원하는 Internet Explorer 8, 9에서 애플리케이션이 올바르게 작동할 가능성을 극대화합니다. 그러나, 쿠키(및 HTTP 세션)의 사용이 필요하지 않은 애플리케이션의 경우, 개발자는 이 값을 "false"로 설정하여 쿠키 전송을 비활성화할 수 있습니다.

이 설정은 애플리케이션이 클라이언트에 쿠키를 필요로 하는지 아닌지에 따라 중요한 역할을 하며, 특히 보안이나 세션 관리 측면에서 고려해야 할 사항입니다.

 

 

setHeartbeatTime

setHeartbeatTime 메소드는 서버가 클라이언트에게 어떠한 메시지도 보내지 않았을 때, 연결이 끊어지지 않도록 하기 위해 서버가 클라이언트에게 하트비트 프레임을 보내야 하는 시간 간격(밀리초 단위)을 설정합니다.

하트비트의 역할
하트비트는 웹소켓이나 유사한 실시간 통신 프로토콜을 사용하는 애플리케이션에서 연결 상태를 유지하는 데 중요한 역할을 합니다. 일정 시간 동안 어떠한 데이터도 교환되지 않으면, 네트워크 장비(예: 로드 밸런서나 프록시 서버)가 연결을 유휴 상태로 간주하고 연결을 종료할 수 있습니다. 하트비트 프레임을 주기적으로 보냄으로써, 애플리케이션은 연결이 여전히 활성화되어 있음을 네트워크 장비에 알려 연결이 끊어지는 것을 방지할 수 있습니다.

기본값
기본적으로 setHeartbeatTime의 값은 25,000밀리초, 즉 25초로 설정되어 있습니다. 이는 서버가 클라이언트로부터 메시지를 받지 않은 채 25초 동안 어떠한 데이터도 전송하지 않았다면, 하트비트 프레임을 보내서 연결을 유지하라는 것을 의미합니다.

설정 예시

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myWebSocketHandler(), "/my-websocket-endpoint")
            .withSockJS()
            .setHeartbeatTime(25000); // 하트비트 간격을 25초로 설정
}

 

이 설정은 실시간 통신을 사용하는 애플리케이션의 성능과 안정성에 직접적인 영향을 미칩니다. 너무 짧은 간격으로 하트비트를 설정하면 불필요한 네트워크 트래픽이 증가할 수 있으며, 너무 긴 간격으로 설정하면 연결이 끊어질 위험이 있습니다. 따라서 애플리케이션의 요구사항과 네트워크 환경을 고려하여 적절한 하트비트 간격을 설정하는 것이 중요합니다.

 

 

setDisconnectDelay 
setDisconnectDelay 메소드는 클라이언트가 서버로부터 데이터를 수신하는 활성 연결을 잃은 후, 클라이언트가 연결이 끊어진 것으로 간주되기 전까지의 시간(밀리초 단위)을 설정합니다.

연결 끊김 지연의 중요성
이 설정은 웹 애플리케이션에서 클라이언트와의 연결 관리에 있어 중요한 역할을 합니다. 예를 들어, 네트워크의 일시적인 문제나 끊김이 발생했을 때, 즉각적으로 클라이언트를 연결이 끊어진 상태로 판단하지 않고 일정 시간을 주어 복구할 기회를 제공합니다. 이렇게 함으로써 클라이언트가 네트워크를 재연결하여 세션을 유지할 수 있는 가능성이 높아집니다.

기본값
기본적으로 setDisconnectDelay의 값은 5,000밀리초, 즉 5초로 설정되어 있습니다. 즉, 서버가 클라이언트로 데이터를 전송할 수 있는 활성 연결이 끊어진 후 5초 동안 클라이언트가 다시 연결되지 않으면, 해당 클라이언트를 연결이 끊어진 것으로 간주합니다.

설정 예시

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myWebSocketHandler(), "/my-websocket-path")
            .withSockJS()
            .setDisconnectDelay(5000); // 연결이 끊어진 것으로 판단하기 전의 지연 시간을 5초로 설정
}

 

이 설정은 특히 모바일 클라이언트나 불안정한 네트워크 환경에서 작업할 때 중요할 수 있습니다. 네트워크 상태가 빈번하게 변할 수 있는 환경에서는 더 긴 지연 시간을 설정하여 연결이 끊어지는 것을 방지하는 것이 좋습니다. 반면, 매우 안정적인 네트워크 환경에서는 이 값을 낮출 수도 있습니다. 하지만 연결 상태를 너무 빠르게 끊어버리면 일시적인 네트워크 문제로 인해 불필요하게 세션을 재생성하는 상황이 발생할 수 있기 때문에, 적절한 값을 설정하는 것이 중요합니다.


setHttpMessageCacheSize
setHttpMessageCacheSize 메소드는 SockJS에서 사용하는 HTTP 폴링이나 스트리밍 전송 시, 서버가 클라이언트의 다음 HTTP 요청을 기다리는 동안 세션에서 캐시할 수 있는 서버-클라이언트 메시지의 수를 설정합니다. 이 속성은 모든 HTTP 전송에 사용됩니다. 스트리밍 전송도 주기적으로 HTTP 요청을 재사용하기 때문입니다.

메시지 캐시의 역할
HTTP 폴링에서 클라이언트는 주기적으로 서버에게 새 메시지가 있는지 확인하기 위해 HTTP 요청을 보냅니다. 서버는 새 메시지가 없으면 즉시 응답하지 않고, 새 메시지가 도착하거나 특정 시간이 경과할 때까지 기다렸다가 응답합니다. 이 때, httpMessageCacheSize는 이 기간 동안 서버가 보내야 할 메시지를 얼마나 많이 저장해둘 수 있는지를 결정합니다.

스트리밍 전송에서도 비슷한 맥락이 적용됩니다. 클라이언트는 한 번의 연결을 통해 지속적으로 데이터를 받지만, 연결이 재활용될 때 메시지 캐시가 유용하게 사용됩니다.

기본값
기본적으로 setHttpMessageCacheSize의 값은 100으로 설정되어 있습니다. 즉, 한 세션에서 최대 100개의 메시지를 캐시할 수 있습니다.

설정 예시

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myWebSocketHandler(), "/my-websocket-path")
            .withSockJS()
            .setHttpMessageCacheSize(100); // HTTP 폴링 대기 중에 캐시할 수 있는 메시지 수를 100으로 설정
}

 

이 설정은 특히 네트워크 지연이나 일시적인 연결 중단 상황에서 클라이언트가 놓칠 수 있는 메시지를 최소화하는 데 중요합니다. 너무 작은 값으로 설정하면 클라이언트가 일부 메시지를 놓칠 수 있고, 너무 큰 값으로 설정하면 서버의 메모리 부담이 커질 수 있으므로, 애플리케이션의 요구사항과 서버의 용량에 맞게 적절한 값을 설정하는 것이 중요합니다.

 

 

setWebSocketEnabled

setWebSocketEnabled 메소드는 서버 측에서 WebSocket 전송을 활성화하거나 비활성화하는 설정을 제공합니다. 이 설정은 주로 로드 밸런서와 같은 인프라가 WebSocket 프로토콜을 지원하지 않을 때 유용합니다. 일부 환경에서는 WebSocket 연결이 잘못 처리되거나 지원되지 않을 수 있으므로, 이러한 경우에 WebSocket 대신 다른 SockJS 지원 전송 방식(예: 폴링)으로 대체할 수 있도록 해줍니다.

기본값
기본적으로 setWebSocketEnabled 옵션의 값은 true로 설정되어 있어, WebSocket이 기본적으로 활성화되어 있음을 의미합니다.

WebSocket 비활성화
만약 애플리케이션이 실행되는 환경에서 WebSocket이 제대로 동작하지 않는다면, 개발자는 이 설정을 false로 설정하여 WebSocket 전송을 비활성화할 수 있습니다. 이렇게 하면 SockJS 클라이언트는 다른 가능한 전송 방법(예: XHR 스트리밍, XHR 폴링 등)을 사용하게 됩니다.

설정 예시

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myWebSocketHandler(), "/my-websocket-endpoint")
            .withSockJS()
            .setWebSocketEnabled(false); // WebSocket 전송을 비활성화
}

 

이 설정을 사용하면, 클라이언트는 WebSocket 연결을 시도하지 않고, SockJS가 제공하는 다른 전송 메커니즘을 사용하여 서버와 통신을 시도하게 됩니다. 이는 로드 밸런서 또는 기타 네트워크 구성 요소가 WebSocket을 지원하지 않을 때 유용하며, 모든 사용자에게 일관된 연결 경험을 제공하는 데 도움이 됩니다.

 

 

setTransportHandlers

setTransportHandlers 메소드는 SockJS 서버 설정에서 사용할 트랜스포트 핸들러를 설정하는 데 사용됩니다. 이 메소드를 통해 개발자는 SockJS 세션에 대한 다양한 전송 방식을 커스터마이즈하고, 기본적으로 제공되는 트랜스포트 대신 특정 트랜스포트 핸들러를 명시적으로 사용할 수 있습니다.

트랜스포트 핸들러의 역할
SockJS는 여러 트랜스포트 메커니즘을 지원하여, 웹소켓이 사용할 수 없는 환경에서도 비슷한 기능을 제공할 수 있도록 합니다. 예를 들어, 웹소켓, HTTP 스트리밍, HTTP 폴링 등이 있습니다. setTransportHandlers 메소드를 사용하여 이러한 트랜스포트 중에서 특정한 것을 선택적으로 사용하도록 설정할 수 있습니다.

사용 예시

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/my-endpoint")
                .withSockJS()
                .setTransportHandlers(
                        new WebSocketTransportHandler(),
                        new XhrStreamingTransportHandler(),
                        new XhrPollingTransportHandler()
                );
    }
}

 

위의 예시에서는 WebSocketTransportHandler, XhrStreamingTransportHandler, XhrPollingTransportHandler를 사용하여 SockJS 세션에 대한 웹소켓, XHR 스트리밍, XHR 폴링 전송을 각각 처리합니다. 이렇게 특정 트랜스포트 핸들러를 설정함으로써, 애플리케이션이 사용할 수 있는 트랜스포트 메커니즘을 명확하게 정의하고 관리할 수 있습니다.

설정의 중요성
이 설정을 통해 개발자는 애플리케이션의 요구사항과 네트워크 환경에 가장 적합한 트랜스포트 방식을 선택하여, 최적의 성능과 호환성을 달성할 수 있습니다. 또한, 특정 트랜스포트 핸들러만을 사용하도록 함으로써 네트워크 리소스의 사용을 최적화하고, 필요하지 않은 트랜스포트 방식을 제외할 수 있습니다.

 

 

setTransportHandlerOverrides

setTransportHandlerOverrides 메소드는 SockJS 서비스에서 사용할 트랜스포트 핸들러를 재정의하는 데 사용됩니다. 이 메소드를 통해 기본적으로 제공되는 트랜스포트 핸들러 대신에 사용자 지정 핸들러를 설정할 수 있습니다. 이를 통해 애플리케이션의 특정 요구사항에 맞게 트랜스포트 메커니즘을 더욱 세밀하게 제어할 수 있습니다.

트랜스포트 핸들러 재정의의 목적
기본적으로 SockJS는 여러 가지 트랜스포트 방식을 지원합니다. 예를 들어 웹소켓, HTTP 스트리밍, HTTP 폴링 등이 있습니다. setTransportHandlerOverrides 메소드를 사용하면, 이러한 기본 핸들러를 사용자가 정의한 핸들러로 대체할 수 있습니다. 이는 기본 동작에 만족하지 못하거나 특수한 행동이 필요한 경우 유용합니다.

사용 예시

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/my-endpoint")
                .withSockJS()
                .setTransportHandlerOverrides(
                        new CustomWebSocketHandler(),
                        new CustomXhrStreamingHandler()
                );
    }
}

 

이 예시에서는 CustomWebSocketHandler와 CustomXhrStreamingHandler라는 사용자 지정 핸들러를 사용하여 기본 웹소켓 및 XHR 스트리밍 핸들러를 대체합니다. 이렇게 하여, 애플리케이션은 표준 동작을 재정의하고 특정 요구사항에 맞춘 처리를 할 수 있습니다.

설정의 중요성
setTransportHandlerOverrides 메소드를 사용하면, 애플리케이션이 트랜스포트 메커니즘을 더 정밀하게 제어하고, 표준 행동을 사용자의 요구에 맞게 조정할 수 있습니다. 이는 애플리케이션의 특정 요구사항, 성능 최적화, 또는 보안 강화를 위해 중요할 수 있습니다.

 

 

setInterceptors
setInterceptors 메소드는 SockJS 서비스에 대한 핸드셰이크(Handshake) 인터셉터를 설정하는 데 사용됩니다. 이 메소드를 통해 개발자는 SockJS 핸드셰이크 과정에 추가적인 로직을 삽입할 수 있습니다. 핸드셰이크 인터셉터는 클라이언트와 서버 간의 초기 연결 설정 과정에서 실행되며, 이를 통해 인증, 로깅, 요청 검증 등의 작업을 수행할 수 있습니다.

핸드셰이크 인터셉터의 역할
핸드셰이크 인터셉터는 연결이 성립되기 전후에 특정 작업을 수행할 수 있게 해줍니다. 예를 들어, 클라이언트의 인증 상태를 검증하거나, 핸드셰이크 요청에 포함된 특정 헤더를 분석할 수 있습니다. 이는 보안이 중요한 애플리케이션에서 특히 유용할 수 있습니다.

사용 예시

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myWebSocketHandler(), "/websocket")
                .setAllowedOrigins("*")
                .withSockJS()
                .setInterceptors(new MyHandshakeInterceptor());
    }

    private WebSocketHandler myWebSocketHandler() {
        return new TextWebSocketHandler();
    }
}

 

이 예시에서 MyHandshakeInterceptor는 사용자 지정 핸드셰이크 인터셉터로, 연결이 설정될 때 특정 로직을 실행합니다. 예를 들어, 이 인터셉터 내에서 클라이언트의 요청 헤더를 검사하여 인증 토큰의 유효성을 확인할 수 있습니다.

설정의 중요성
핸드셰이크 인터셉터는 SockJS 연결 프로세스를 더욱 유연하고 제어 가능하게 만들어 줍니다. 특히, 보안, 사용자 인증, 요청 검증과 같이 중요한 과정을 커스터마이징하고 싶을 때 유용합니다. 이런 방식으로 애플리케이션의 특정 요구사항을 충족시키면서도 웹소켓 연결의 효율성과 안정성을 보장할 수 있습니다.

 

 

setAllowedOrigins 

setAllowedOrigins 메소드는 SockJS 서비스에서 허용되는 Origin 헤더 값을 설정하는 데 사용됩니다. 이 설정은 크로스 오리진 리소스 공유(CORS: Cross-Origin Resource Sharing) 정책과 관련이 있습니다. CORS 정책은 웹 페이지가 다른 도메인의 리소스에 접근할 수 있는 조건을 브라우저에 알려주는 메커니즘입니다.

CORS 및 Origin 헤더
웹 애플리케이션에서 다른 도메인, 프로토콜 또는 포트를 가진 서버로부터 리소스를 요청할 때, 브라우저는 Origin 헤더를 포함한 HTTP 요청을 보냅니다. 서버는 이 요청을 수신한 후, Access-Control-Allow-Origin 헤더를 포함한 응답을 통해 해당 요청을 허용할 지 여부를 결정합니다.

사용 예시
setAllowedOrigins 메소드를 사용하면, 서버가 요청을 수락할 특정 출처(도메인, 프로토콜, 포트)를 명시적으로 지정할 수 있습니다. 예를 들어, 당신의 서비스가 https://example.com과 https://example.org에서 오는 요청만을 허용하도록 설정하고 싶다면, 다음과 같이 설정할 수 있습니다

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myWebSocketHandler(), "/websocket")
            .setAllowedOrigins("https://example.com", "https://example.org")
            .withSockJS();
}

 

이렇게 설정함으로써, https://example.com과 https://example.org에서만 서버로의 웹소켓 연결을 허용하게 됩니다. 다른 도메인에서 오는 연결 요청은 거부됩니다.

보안 측면의 중요성
이 설정은 보안 측면에서 중요합니다. 원하지 않는 출처로부터의 요청을 차단함으로써, 애플리케이션을 CSRF(크로스 사이트 요청 위조) 공격과 같은 보안 위협으로부터 보호할 수 있습니다. 따라서, 애플리케이션에 적절한 CORS 정책을 구현하는 것은 중요한 보안 고려사항 중 하나입니다.

 

 

setAllowedOriginPatterns

setAllowedOriginPatterns 메소드는 SockJS 서비스에서 허용되는 Origin 헤더 값의 패턴을 설정하는 데 사용됩니다. 이는 Spring Framework 5.3.2 버전부터 도입되었습니다. 이 기능을 사용하면 정규 표현식과 같은 패턴을 이용하여, 허용되는 도메인을 더 유연하게 지정할 수 있습니다.

기능의 중요성
이 메소드는 setAllowedOrigins와 비슷한 역할을 하지만, 도메인 이름에 패턴을 사용할 수 있다는 점에서 더 유연합니다. 예를 들어, 여러 서브 도메인에서 오는 요청을 허용해야 할 경우, 각각을 일일이 명시하는 대신 패턴을 사용하여 쉽게 설정할 수 있습니다.

사용 예시
만약 여러분이 *.example.com (여기서 *는 어떤 서브 도메인도 될 수 있음)에서 오는 모든 요청을 허용하고 싶다면, 다음과 같이 설정할 수 있습니다:

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myWebSocketHandler(), "/websocket")
            .setAllowedOriginPatterns("https://*.example.com")
            .withSockJS();
}

 

이 설정으로 example.com의 모든 서브 도메인에서 오는 요청이 허용됩니다.

 

보안 관련 고려사항
패턴을 사용할 때는 보안을 신중하게 고려해야 합니다. 너무 광범위한 패턴을 설정하면 예상치 못한 도메인에서 오는 요청을 허용하게 될 수 있으므로, 실제 비즈니스 요구사항에 맞게 적절한 수준의 패턴을 사용하는 것이 중요합니다.

setAllowedOriginPatterns는 특히 큰 규모의 웹 애플리케이션에서 유용하게 사용될 수 있으며, 보안과 편의성 사이의 균형을 맞추는 데 도움을 줄 수 있습니다.

 

 

setSuppressCors 

setSuppressCors 메소드는 SockJS 서비스에서 자동으로 추가되는 CORS(크로스 오리진 리소스 공유) 헤더를 비활성화하는 옵션을 설정합니다. 이 메소드는 Spring Framework 5.3.23 버전부터 사용할 수 있습니다. 기본적으로 이 값은 false로 설정되어 있어, SockJS 요청에 대해 CORS 헤더가 자동으로 추가됩니다.

CORS 헤더 자동 추가
CORS 정책은 웹 애플리케이션에서 다른 도메인의 리소스에 접근할 수 있는 규칙을 정의합니다. SockJS 서버 설정에서 CORS 헤더 자동 추가 기능이 활성화되어 있으면 (suppressCors가 false인 경우), 서버는 응답에 적절한 CORS 헤더를 자동으로 포함시켜, 요청이 다른 도메인에서 온 것이라도 처리할 수 있도록 합니다.

CORS 헤더 자동 추가 비활성화
setSuppressCors를 true로 설정하면, SockJS 서비스는 CORS 헤더를 자동으로 추가하지 않습니다. 이는 특정 상황에서, 예를 들어 CORS 정책을 수동으로 더 세밀하게 제어하고자 할 때 유용할 수 있습니다. 이 설정을 통해 개발자는 애플리케이션 레벨에서 CORS 관련 헤더를 직접 관리할 수 있습니다.

설정 예시

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(myWebSocketHandler(), "/websocket")
            .withSockJS()
            .setSuppressCors(true); // SockJS 요청에 대한 CORS 헤더 자동 추가 비활성화
}

 

이 예시에서는 SockJS 서버가 CORS 헤더를 자동으로 추가하는 것을 비활성화합니다. 이 설정은 CORS 정책을 애플리케이션에서 직접 제어하고자 할 때 특히 중요합니다.

보안 및 구성 관련 고려사항
setSuppressCors 설정을 사용할 때는 보안과 애플리케이션의 CORS 요구사항을 신중하게 고려해야 합니다. CORS 정책 을 적절하게 관리하지 않으면 보안 취약점이 발생할 수 있으므로, 이 옵션을 사용할 때는 애플리케이션의 보안 요구사항을 충족시키는 방식으로 CORS를 관리해야 합니다.

 

 

setMessageCodec
setMessageCodec 메소드는 SockJS 메시지를 인코딩하고 디코딩하는 데 사용되는 코덱(codec)을 설정하는 데 사용됩니다. Spring Framework 4.1 버전부터 이 기능이 제공됩니다.

코덱의 역할
코덱은 데이터를 한 형식에서 다른 형식으로 변환하는 기능을 합니다. SockJS 통신에서 메시지 코덱은 서버와 클라이언트 간에 교환되는 메시지의 인코딩(서버가 클라이언트로 데이터를 보낼 때 사용)과 디코딩(서버가 클라이언트로부터 데이터를 받을 때 사용)을 담당합니다.

기본 코덱
기본적으로 Jackson2SockJsMessageCodec가 사용되며, 이는 Jackson JSON 라이브러리를 사용하여 메시지를 JSON 형식으로 인코딩 및 디코딩합니다. 따라서, 이 코덱을 사용하려면 클래스패스에 Jackson 라이브러리가 존재해야 합니다.

사용자 정의 코덱 설정
다른 메시지 포맷이나 인코딩/디코딩 방식을 사용하려는 경우, 사용자 정의 코덱을 구현하고 이를 setMessageCodec 메소드를 통해 설정할 수 있습니다. 예를 들어, 사용자 정의 JSON 처리 라이브러리 또는 다른 데이터 포맷을 사용하려는 경우에 이를 적용할 수 있습니다.

설정 예시

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myWebSocketHandler(), "/websocket")
                .withSockJS()
                .setMessageCodec(myCustomCodec());
    }

    private SockJsMessageCodec myCustomCodec() {
        return new MyCustomSockJsMessageCodec();
    }

    private WebSocketHandler myWebSocketHandler() {
        return new TextWebSocketHandler();
    }
}

 

이 코드에서 MyCustomSockJsMessageCodec은 사용자가 정의한 코덱이며, SockJS 메시지를 처리하는 데 사용됩니다. 이 방법으로 메시지 처리를 애플리케이션의 특정 요구사항에 맞출 수 있습니다.

 

 

getSockJsService 

getSockJsService 메소드는 SockJS 서비스의 인스턴스를 가져오는 데 사용됩니다. 이 메소드는 일반적으로 SockJS 구성 내부에서 사용되며, 개발자가 SockJS 서비스의 인스턴스에 접근하고자 할 때 유용합니다.

SockJsService의 역할
SockJsService 인터페이스는 SockJS 프로토콜을 구현하는 서버 측 컴포넌트의 핵심입니다. 이 서비스를 통해 웹소켓, HTTP 스트리밍, HTTP 폴링 등 다양한 트랜스포트 방식을 관리하고, 클라이언트와의 통신 세션을 처리합니다.

사용 시나리오
getSockJsService 메소드의 사용은 대부분 내부 구현이나 고급 구성에서 필요합니다. 예를 들어, SockJS 서비스의 상세한 동작을 프로그래매틱하게 조사하거나 수정해야 할 때, 이 메소드를 통해 해당 인스턴스에 접근할 수 있습니다.

예시 코드
실제로 getSockJsService 메소드를 사용하는 일반적인 코드 예제는 드물지만, 이 메소드의 사용 예는 다음과 같을 수 있습니다:

public class MyWebSocketConfig {

    private SockJsServiceRegistration sockJsServiceRegistration;

    public MyWebSocketConfig(SockJsServiceRegistration registration) {
        this.sockJsServiceRegistration = registration;
    }

    public void doSomethingWithSockJsService() {
        SockJsService sockJsService = sockJsServiceRegistration.getSockJsService();
        // SockJsService 인스턴스를 사용하여 추가적인 설정이나 조작 수행
    }
}

 

이 예제에서는 SockJsServiceRegistration 객체로부터 SockJsService 인스턴스를 얻어내어, 필요에 따라 추가 설정이나 조작을 할 수 있습니다.

결론
getSockJsService 메소드는 SockJS 서비스의 인스턴스를 직접적으로 다룰 필요가 있을 때 중요하게 사용됩니다. 이를 통 해 SockJS 서비스의 상세한 구성이나 동작을 제어할 수 있습니다.

 

 

getTaskScheduler 

getTaskScheduler 메소드는 구성된 경우 TaskScheduler 인스턴스를 반환합니다. 이 메소드는 SockJS 서비스 또는 웹소켓 설정에서 사용되는 태스크 스케줄러를 가져올 때 사용됩니다.

TaskScheduler의 역할
TaskScheduler는 주기적인 작업 실행, 지연된 실행, 혹은 특정 시간에 한 번 실행되는 작업 스케줄링에 사용됩니다. 웹소켓과 SockJS 컨텍스트에서는 주로 하트비트 전송, 타임아웃 처리 등의 반복적인 태스크를 관리하는 데 사용됩니다.

사용 시나리오
getTaskScheduler 메소드는 스케줄러가 이미 설정되어 있는지 확인하고, 설정된 경우 해당 TaskScheduler 인스턴스에 접근하여 추가적인 스케줄링 작업을 설정하거나 기존의 스케줄링을 조정할 때 유용합니다.

예시 코드
실제 구현에서 getTaskScheduler 메소드를 사용하는 방법은 다음과 같을 수 있습니다

public class MyWebSocketConfig {

    private SockJsServiceRegistration sockJsServiceRegistration;

    public MyWebSocketConfig(SockJsServiceRegistration registration) {
        this.sockJsServiceRegistration = registration;
    }

    public void configureTasks() {
        TaskScheduler scheduler = sockJsServiceRegistration.getTaskScheduler();
        if (scheduler != null) {
            // TaskScheduler 인스턴스를 사용하여 작업 스케줄링 설정
        }
    }
}

 

이 코드에서는 SockJsServiceRegistration 객체를 통해 TaskScheduler 인스턴스를 가져오고, 이 인스턴스가 null이 아닌 경우에만 작업 스케줄링 관련 설정을 수행합니다.

결론
getTaskScheduler 메소드는 웹소켓 또는 SockJS 구성에서 이미 설정된 TaskScheduler 인스턴스를 필요로 할 때 사용됩니다. 이를 통해 개발자는 스케줄링 관련 로직을 더 세밀하게 제어할 수 있습니다.

'항해 99 > Spring' 카테고리의 다른 글

WebSocket - STOMP 2  (0) 2024.03.30
WebSocket - STOMP 1  (1) 2024.03.29
WebSocket - 기본 websocket  (0) 2024.03.27
Redis  (1) 2024.03.25
MapStruct  (0) 2024.03.22