Java/Spring

[삽질] stomp, sockjs를 이용하여 websocket 연결 시 info 가 404로 나오는 경우

체리필터 2018. 3. 13. 15:46
728x90
반응형

WebSocket을 이용하여 특정 내용을 처리하는 로직을 개발 중에 삽질한 내용을 정리 차원에서 올린다.

클라이언트는 SockJS와 stompClient를 이용하였고, 서버는 Spring에서 기본적으로 정리한 내용을 크게 바꾸지 않은 상태로 코딩 하였다.

전반적으로 코드의 내용은 https://spring.io/guides/gs/messaging-stomp-websocket/ 에서 나오는 내용과 거의 다르지 않다.

다만 해당 내용을 코딩 중에 sockjs에서 websocket 서버의 "endpoint/info?timestamp" 와 같은 주소를 찾지 못하는 경우가 발생 했다.

이로 인해 서버의 특정 모듈 Dependency가 잘못 되던가, 알지 못하는 문제로 인해 발생 하는 것인줄 알고 프로젝트를 Spring Boot로 싹 다 새로 만들게 되었다.

 

스프링 부트로 만든 상태에서 테스트 해 보니 이상 없이 돌아 갔는데, 해당 내용을 실제 개발 플랫폼에 적용하려고 보니 다시 info 페이지가 404 에러를 내 뿜는게 아닌가 ㅠㅠ

https와 http 문제라고 생각해서 프로토콜도 맞추었지만 현상은 해결 되지 않았다.

 

그런데 크롬의 개발자 도구를 자세히 살펴 보니 info 호출 시 response에 "Invalid CORS request" 라고 response가 뜨는 것을 발견 ㅠㅠ

도메인 문제인 것 같은데...

그렇다면 서버에서 어떻게 설정을 해 주어야 다른 도메인에서도 접근 가능하도록 해 줄 수 있는것일까? 하고 다시 구글링 돌입...

 

결국 https://spring.io/guides/gs/messaging-stomp-websocket/#_configure_spring_for_stomp_messaging 부분에서 보이는 것 처럼 endpoint 설정 시 접근할 수 있는 도메인을 추가로 정해 주면 되는 것이었다.

내가 찾은 stackoverflow의 좌표는 https://stackoverflow.com/questions/30502943/spring-websocket-connecting-with-sockjs-to-a-different-domain

 

이전 코드

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
	// WebSocketMessageBrokerConfigurer.super.registerStompEndpoints(registry);
	registry.addEndpoint("/stork-websocket").withSockJS();
}

 

수정 된 코드

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
	// WebSocketMessageBrokerConfigurer.super.registerStompEndpoints(registry);
	registry.addEndpoint("/stork-websocket").setAllowedOrigins("*").withSockJS();
}

 

 

결국 setAllowedOrigins("*") 하나를 위해서 2주 정도 삽질을 하게 된 ㅠㅠ

물론 이것 뿐 아니라... 현재 웹 소켓에 동시 접속된 유저 수를 구하기 위해 프로젝트를 새롭게 구성할 필요가 있긴 했다.

 

동접자 구하는 소스는 참고로 아래와 같다.

다만... 공식적인 소스가 아니라 그냥 디버깅 해 가면서 만든 소스라서 정확하게 동작 안 할 수 도 있다.

 

Websocket Config 정의하는 Class 내에 아래와 같이 inbound interceptor를 정의 한다.

@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
	registration.interceptors(new WebSocketInterceptor());
}

 

 

그리고 나서 인터셉터에서 세션을 Set에 담아 size를 구해와서 사용하면 된다.

package com.auctionblue.bluemessenger.interceptor;

import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.ChannelInterceptorAdapter;

public class WebSocketInterceptor extends ChannelInterceptorAdapter {
	Set<String> sessionSet = new HashSet<>();

	@Override
	public Message<?> preSend(Message<?> message, MessageChannel channel) {
		String simpMessageType = String.valueOf(message.getHeaders().get("simpMessageType"));
		
		if(StringUtils.equals(simpMessageType, "CONNECT")) {
			String simpSessionId = String.valueOf(message.getHeaders().get("simpSessionId"));
			sessionSet.add(simpSessionId);
		} else if(StringUtils.equals(simpMessageType, "DISCONNECT")) {
			String simpSessionId = String.valueOf(message.getHeaders().get("simpSessionId"));
			sessionSet.remove(simpSessionId);
		}
		
		int uniqueJoinSessionCount = sessionSet.size();
		System.out.println(uniqueJoinSessionCount);
		
		return super.preSend(message, channel);
	}
}

 

728x90
반응형