웹소켓 채팅, withSocketJs()에서 발생하는 에러

Alex·2024년 10월 24일
1

Plaything

목록 보기
1/118

Plaything 기능의 핵심 중 하나는 일대일 채팅이다.
채팅을 위해서는 웹소켓-stomp를 사용했다.

우선, 이 라이브러리들을 사용한 이유를 정리한다.

Http Polling 방식은 커넥션을 계속 맺고 있지 않아서 서버 리소스를 절약할 수는 있다.
다만, 일정 주기로 클라이언트에서 메시지를 가져가는 방식이라서, 메시지가 전달되기 까지 일정 시간 지연이 발생한다.

클라이언트에서 api요청을 주면, 연결을 맺고 서버가 응답을 준다. 작업이 끝난다.

HTTP는 요청과 응답에 연결에 대한 많은 정보를 담아서 보낸다.(매번 연결을 해야해서)
네트워크 I/O가 웹소켓에 비해서 비싸다.(많은 정보가 오간다는 뜻)


위 사진처럼 요청과 응답에 정보가 많이 담긴다.

Web Socket을 쓰면 리소스를 최대한 절약할 수 있다.
실시간 채팅에서 많이 쓰는 방식으로, 유저와 서버간 커넥션이 맺어져 있는 상태라서 메시지가 발생하는 즉시 전달 가능하다.
다만, 서버와 연결이 지속돼야 하므로 서버당 처리할 수 있는 클라이언트의 수에 제한이 있다.

트래픽이 빈번한 요청에 경우에는 웹소켓을 쓸 수 있다고 한다.

웹소켓은 한번 연결되면 커넥션이 끊기지 않는다.
이벤트를 지속적으로 모니터링한다.

웹소켓은 처음 한번만 연결 정보가 담긴다.
그래서 그 이후로는 정보가 많이 안 담긴다. 네트워크 I/O가 더 저렴해진다.

STOMP는 웹 소켓의 메시지 타입을 정의하는 텍스트 기반 메시징 프로토콜이다.
기본적으로 pub/sub 구조로 되어 있기 때문에, 추후 카프카 같이 외부 Messaging Queue를 활용해 고도화시킬 때 편리하다.

나중에 서버가 여러대가 되면 메시지 브로커를 별도로 써야 한다.

그래서 어떤 문제가 있었는데?

웹 소켓으로 채팅을 연결했을 때 개발자 도구에서 STOMP 연결이 없다고 떴다.

코드에서 withSockJs()를 빼버리면 웹 소켓에 연결돼서 정상 작동한다.

그런데, 왜 이걸 빼야만 작동하는지 그 이유를 모르겠다.

로그를 살펴보자

withSockJs()을 사용한 채로 한번 로그를 살펴보고 디버깅을 해보자.

logging.level.org.springframework.web.socket: DEBUG
logging.level.org.springframework.messaging: DEBUG
logging.level.org.springframework.web.socket.sockjs: TRACE

우선, 로그가 어떻게 뜨는지 확인해보기로 했다.

저것만으로는 어떤 문제가 있는지 확인하기가 어려웠다.

TransportHandlingSockJsService를 디버깅해서 SocketJs가 실핼되고 있는지 확인했다. running이 true로 바뀌고, 이에 대한 핸들러들이 있는 것으로 보였다.

여기서 작업이 시작돼야 한다고 하는데 브레이킹포인트를 걸어도 여기까지 오지 않았다.

여기서 리퀘스트를 핸들하는 과정을 살펴보자.

여기서 처음 if분기점을 보면 sockJsPath가 "" 즉 비어있어서 else로 넘어간다.

여기서

이부분에 걸리고 종료가 된다. 그 아래에서 메시지를 SocketJS와 연결되는 부분으로 넘어가지 않는 거 같다.

클로드가 말한 내용을 보니 원래는 저렇게 동작하는 게 맞는 거 같고
클라이언트에서 처음부터 WebSocket으로 연결하려고 해서 에러가 발생한 것으로 보인다.

const C = new StompJs.Client({
    brokerURL: "ws://localhost:7002/ws-stomp",  // 여기가 문제
    ...
});
const C = new StompJs.Client({
    webSocketFactory: () => new SockJS('http://localhost:7002/ws-stomp'),  // SockJS 사용
    connectHeaders: {
        Authorization: `Bearer ${authCookie}`,
    },
    reconnectDelay: 5000,
    onConnect: () => {
        console.log("connected");
        subscribe(C);
    },
    ...
});

저렇게 바꾸니 이제 정상적으로 메시지가 전달된다!

근데 보니까 웹소켓으로 연결이 된 게 아니다.
SocketJs로 연결되고 있다.

withSocketJs()설정은 웹 소켓이 지원되지 않을 때 SocketJs를 쓰도록하는 것인데 계속 저 설정을 붙이면 웹 소켓을 쓰지 않고 있다...

이 문제는 다음 글에서 해결해보자.

profile
답을 찾기 위해서 노력하는 사람

0개의 댓글