개발 낙서장

[TIL] 내일배움캠프 82일차 - WebSocket Connection Failed 본문

Java/Sparta

[TIL] 내일배움캠프 82일차 - WebSocket Connection Failed

권승준 2024. 4. 25. 21:42

 

 

오늘의 학습 키워드📚

Connection Failed

진짜 환장할 오류가 발생했었다.
잘 되던 웹소켓이 배포 환경에서 HTTPS 프로토콜로 바꾸니 웹소켓 연결이 되지 않는 것이다.
로컬에서도 잘 되고 HTTP 프로토콜에서도 잘 동작하는데 배포 환경의 HTTPS 프로토콜에서만 동작하지 않았다.
오류 체크를 위해 레포지토리를 Fork 해서 로컬에서 HTTPS 세팅을 하고 실행했는데 연결이 잘 돼서 더 당황했다.

    useEffect(() => {
        if (currentRoom !== null && stompClient === null) {
            const client = new StompJs.Client({
                brokerURL: `ws://${window.location.hostname}:8080/gs-guide-websocket`,
                onConnect: async message => {
                    console.log(message);
                    client.subscribe(
                        `/topic/chat-rooms/${currentRoom.chatRoomId}`,
                        onMessageReceived);
                    try {
                        const response = await getRoomMessages(
                            currentRoom.chatRoomId);
                        setRoomMessages(response.data.data);
                        setState(chattingAppState.채팅방입장);
                    } catch (error) {
                        alert("채팅방 정보 로드에 실패했습니다.");
                    }
                },
                onWebSocketError: error => {
                    alert('웹 소켓 에러');
                    setCurrentRoom(null);
                },
                onStompError: frame => {
                    alert('웹 소켓 에러');
                    setCurrentRoom(-1);
                },
            });

            client.activate();
            setStompClient(client);
        } else if (currentRoom === null && stompClient) {
            stompClient.deactivate();
            setStompClient(null);
        }
    }, [currentRoom]);

기존 연결 코드인데 StompJS 모듈을 사용해 Endpoint URL로 연결을 시도하고 처리하는 로직이다.
하지만 HTTPS에서는 wss 프로토콜로 연결을 시도해야 된다고 해서 코드를 수정했다.

            const protocol = window.location.protocol === "https:"
                ? "wss:"
                : "ws:";

            const domainUrl = window.location.port === ""
                ? window.location.hostname
                : `${window.location.hostname}:${window.location.port}`;

현재 프로토콜과 도메인, 포트 번호를 동적으로 확인하여 URL을 생성했다.
하지만 계속해서 connection failed 오류가 발생했고 어떠한 오류 메세지도 발생하지 않아 계속해서 헤매고 있었다.

시도한 방법은 총 3가지이다.

1. 환경 변수 설정(실패)

https://github.com/facebook/create-react-app/issues/11897

 

Hot reload doesn't work in Gitpod after fresh CRA install · Issue #11897 · facebook/create-react-app

Describe the bug I set up a fresh React project in a Gitpod workspace using create-react-app. After starting the dev server with npm start, hot reload doesn't work. Changes to App.tsx are only rend...

github.com

페이스북 리액트 깃허브에 있는 이슈인데 여기서도 동일하게 HTTP에서는 동작하다가 HTTPS로 바꾸니 웹소켓 연결이 되지 않는다는 문제였다.
댓글들을 살펴보던 중 환경 변수에 해당 값을 추가하라는 댓글이 있었다.

WDS_SOCKET_PORT=0

웹소켓 포트를 설정해주는 것인데 클라이언트에서 windows.location.port를 웹소켓 포트로 설정해주어 연결이 가능하다고 한다.
실제로 이슈 댓글들을 살펴보면 이 방법으로 다 해결했다고 한다.

하지만 .env 파일에 추가하여 실행해봤는데 변한 것은 없었다...

2. 프록시 설정(실패)

프론트에서 프록시를 설정해주는 이유는 프론트에서 동작하는 포트와 백에서 동작하는 포트가 다르기 때문이다.
따라서 CORS 문제가 발생할 수 있기에 프록시를 설정하여 프론트와 백의 통신이 가능하도록 해주는 것이다.

HTTPS랑 프록시랑 무슨 관련인데? 싶었지만 어느 깃허브를 탐방하던 중 프록시로 wss 연결을 허용?해주는 설정을 볼 수 있었고 바로 적용했다.

const {proxy} = require('http-proxy-middleware');

module.exports = function(app) {
    app.use(
        proxy('/gs-guide-websocket', {
            target: 'wss://www.wuzuzu.shop/gs-guide-websocket',
            ws: true,
            changeOrigin: true,
            secure: false,
            pathRewrite: {
                '^/gs-guide-websocket': '',
            },
        }),
    );
};

웹소켓 엔드포인트로 들어온 요청을 wss로 넘겨주는? 역할을 하는 것 같다.
하지만 이 역시 실패했다.

3. 모듈 바꿔주기(성공!!!)

에러 메세지도 안 뜨고 사람들이 해결했던 방법으로도 안 되고 도저히 갈피를 잡지 못하고 있었다.
그러던 중 처음 웹소켓 연결을 시도했던 때가 생각나서 모듈 문제인가? 싶어 연결 부분을 갈아엎었다.

기존에는 위에 있듯이 StompJS 모듈만을 사용하여 클라이언트를 생성하고 있었다.
이 방법으로도 많이 연결을 하지만 SockJS와 같이 사용해 연결하는 방법도 있었다.

https://stomp-js.github.io/guide/stompjs/rx-stomp/using-stomp-with-sockjs.html

 

Using STOMP with SockJS

There are a large number of obsolete (and copied from one another) examples for these libraries that use SockJS. In reality, there is very little chance that you need SockJS. Unless you know, for sure, you do not need SockJS.

stomp-js.github.io

SockJS 공식 문서를 바탕으로 세팅해주고 코드를 수정했다.
(의존성 추가, JS 라이브러리 세팅, npm 모듈을 설치해주어야 한다)

WebSocketConfig.java

    // STOMP 엔드포인트 등록
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/gs-guide-websocket")
            .setAllowedOriginPatterns("*")
            .withSockJS(); // 핸드셰이크 엔드포인트 설정
    }

주의해야 할 점은 setAllowedOrigins("*")를 사용하면 에러가 발생한다.

ChattingApp.js

    useEffect(() => {
        if (currentRoom !== null && stompClient === null) {
            const socket = new SockJS(`/gs-guide-websocket`);
            const client = StompJs.over(socket);

            client.connect({}, async (frame) => {
                console.log(frame);
                client.subscribe(
                    `/topic/chat-rooms/${currentRoom.chatRoomId}`,
                    onMessageReceived
                );
                try {
                    const response = await getRoomMessages(
                        currentRoom.chatRoomId
                    );
                    setRoomMessages(response.data.data);
                    setState(chattingAppState.채팅방입장);
                } catch (error) {
                    alert("채팅방 정보 로드에 실패했습니다.");
                }
            }, (error) => {
                alert('웹 소켓 에러');
                setCurrentRoom(null);
            });

            setStompClient(client);
        } else if (currentRoom === null && stompClient) {
            stompClient.disconnect(() => {
                setStompClient(null);
            });
        }
    }, [currentRoom]);

엔드포인트로 소켓을 생성하고 해당 소켓으로 Stomp 클라이언트를 생성해 연결해주었다.

연결이 돼서 콘솔에 잘 찍혔다.
아직도 왜 에러가 발생했었는지 원인은 잘 모르겠지만 아마 StompJS 모듈에서 HTTPS 관련 설정이 따로 필요한 것으로 보인다. 배포 환경과 로컬은 다르므로 AWS 인증서 문제인지 뭔지 자세히는 모르겠다.

참고

https://velog.io/@9_miin/React-https-%EC%A0%81%EC%9A%A9-%ED%9B%84-WebSocket-connection-to-failed-%EC%9D%B4%EC%8A%88

 

[React] https 적용 후 WebSocket connection to failed 이슈

WebSocket connection to failed 에러 이전에 배포 했던 hyperledger indy 관련 프로젝트를 ec2를 통해 진행하고 route53에서 도메인 등록을 해놨는데 https설정을 해본적이 없어서 연습삼아 도전. acm을 통해 SSL인

velog.io

https://velog.io/@yun12343/WebSocket-STOMP-SockJS-%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%B1%84%ED%8C%85-%EC%A0%95%EB%A6%AC

 

WebSocket / STOMP / SockJS 를 활용한 채팅 정리

WebSocket / STOMP / SockJS 를 활용한 채팅 정리

velog.io


오늘의 회고💬

며칠 동안 해결이 안 되고 방법도 전혀 모르겠어서 너무 답답했었는데 마지막에 극적으로 해결돼서 너무 다행이고 속 시원하다.

 

내일의 계획📜

화면 부분 마지막으로 정리하고 발표 준비를 할 것 같다.

Comments