-
Notifications
You must be signed in to change notification settings - Fork 6
Knowledge: In WebSocket
웹소켓 핸드쉐이킹 후 구독을 하는데 처음 컴포넌트가 마운트 될 때 웹소켓 연결이 되지 않았고, 코드를 한 번 아무곳이나 더미로 수정한 후 리액트의 핫 리로딩을 강제로 시켜줬을때 비로소 웹소켓 연결과 구독이 실행되었다. 한번 왜 강제로 리랜더를 시켜줘야할까?
프로젝트로 리액트에서 웹소켓을 이용할 일이 있었다. 백엔드는 스프링으로 구현되어있기 떄문에 스프링에 최적화된 stomp 를 사용했다.
인스타그램의 Direct Message 와 같은 기능을 구현하고 있어서 나의 이름으로 온 메시지를 항상 확인해야한다.그러므로 컴포넌트가 마운트 되자마자 나의 이름을 항상 구독하고 있어야한다.
sockjs-client
라이브러리와 stompjs
라이브러리를 사용했다.
왜 강제로 리랜더를 시켜줘야 비로소 웹소켓이 연결 및 구동이 될까? 라는 고민을 했는데 처음에 핸드쉐이킹 하는 부분에 오류가 있었다.
원래는 위 사진과 같이 컴포넌트의 바깥쪽에 상수와 변수를 선언했다.
아래와 같이 Direct Component(웹소켓 연결하는 컴포넌트) 안에 핸드쉐이킹을 하는 변수와 상수를 선언해주자 useEffect 를 통해서 웹소켓 연결하는 코드가 제대로 실행되었다!
Websocket - sockjs - InvalidStateError: The connection has not been established yet
메시지를 보내는 부분의 코드는 다음과 같다.
const sendMessage = () => {
// Todo : axios
stompClient.send("/pub/messages", {}, JSON.stringify({
"message": message,
"senderId": 7,
"receiverId": 14,
"roomId": 5,
}));
}
setMessage("");
};
위 처럼 코드를 작성하니 메세지를 보내는 trigger 를 발생시킬때마다 위와같은 오류가 나왔다.
async await 도 사용해보고 여러가지 찾아본결과 임의로 시간을 지연시키는 등 편법을 써봤지만 오류해결에는 도움이 안되었다.
위 에러문구를 잘 해석해보면 아직 웹소켓이 준비가 되지않았는데, 계속 trigger 를 시키니깐 오류가 난것이였다. 여러가지 찾아본 결과 Stomp.Client 안에는 ws.readyState 라는 integer 값이 있으며, 연결되었을 경우에(준비가된 경우) 1을 반환한다고 한다. 그 사실을 이용해서 새로운 함수를 만들어줬다! 이 함수를 이용해서 기존의 send 를 감싸줄 것이다! 코드는 직관적이다.
// 웹소켓이 연결될 때 까지 실행하는 함수
function waitForConnection(stompClient:Stomp.Client, callback :any) {
setTimeout(
function () {
// 연결되었을 때 콜백함수 실행
if (stompClient.ws.readyState === 1) {
callback();
// 연결이 안 되었으면 재호출
} else {
waitForConnection(stompClient, callback);
}
},
1 // 밀리초 간격으로 실행
);
}
아까 send 만 있던 함수를 새롭게 정의한 waitForConnection 함수로 감싸주자
const sendMessage = () => {
// Todo : axios
waitForConnection(stompClient,function() {
stompClient.send("/pub/messages", {}, JSON.stringify({
"message": message,
"senderId": 7,
"receiverId": 14,
"roomId": 5,
}));
})
setMessage("");
};
위처럼하면 몇번이고 메세지를 보내도 아까와 같은 오류가 뜨지 않는것을 확인했다!
프로젝트가 끝나면 전체 웹소켓에 대한 글을 작성하겠습니다.