Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.

Commit d42e653

Browse files
authored
✨ Feature: 웹소켓 재연결 로직 추가
1 parent 3b8de1e commit d42e653

File tree

2 files changed

+244
-78
lines changed

2 files changed

+244
-78
lines changed

src/app/news/detail/[id]/page.js

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ const NewsDetailPage = () => {
3939
const [showErrorToast, setShowErrorToast] = useState(false);
4040
const [errorMessage, setErrorMessage] = useState('');
4141
const socketRef = useRef(null);
42+
const reconnectAttemptsRef = useRef(0);
43+
const MAX_RECONNECT_ATTEMPTS = 3;
44+
const RECONNECT_DELAY = 5000; // 5초
4245
const [highlightSegments, setHighlightSegments] = useState([]);
4346

4447
// 인용구 클릭 시 해당 문단으로 스크롤 이동하는 함수
@@ -101,34 +104,91 @@ const NewsDetailPage = () => {
101104
fetchNewsDetail();
102105
}, [params.id]);
103106

107+
const connectWebSocket = () => {
108+
return new Promise((resolve, reject) => {
109+
const socket = new SockJS(SOCKET_CONFIG.ENDPOINT);
110+
const client = Stomp.over(socket);
111+
112+
client.connect(
113+
{ type: SOCKET_CONNECTION_TYPE.PUBLIC },
114+
() => resolve(client),
115+
(error) => reject(error)
116+
);
117+
});
118+
};
119+
120+
const subscribeToChat = (client) => {
121+
return new Promise((resolve) => {
122+
client.subscribe(`/topic/chat.${params.id}.count`, ({ body }) => {
123+
const { count } = JSON.parse(body);
124+
setUserCount(count);
125+
});
126+
resolve(client);
127+
});
128+
};
129+
130+
const initializeChatCount = (client) => {
131+
client.send(
132+
`/app/chat.initCount.${params.id}`,
133+
{},
134+
""
135+
);
136+
};
137+
138+
const setupConnectionCloseHandler = (client) => {
139+
client.onWebSocketClose = (event) => {
140+
console.log("WebSocket 연결이 종료되었습니다.", event);
141+
142+
if (event.code === 1002) {
143+
console.log("의도하지 않은 연결 종료 (code: 1002), 재연결 시도");
144+
145+
if (reconnectAttemptsRef.current < MAX_RECONNECT_ATTEMPTS) {
146+
reconnectAttemptsRef.current += 1;
147+
console.log(`재연결 시도 ${reconnectAttemptsRef.current}/${MAX_RECONNECT_ATTEMPTS}`);
148+
149+
setTimeout(async () => {
150+
try {
151+
const newClient = await connectWebSocket();
152+
await subscribeToChat(newClient);
153+
initializeChatCount(newClient);
154+
setupConnectionCloseHandler(newClient);
155+
socketRef.current = newClient;
156+
reconnectAttemptsRef.current = 0; // 재연결 성공 시 카운트 초기화
157+
} catch (error) {
158+
console.error("WebSocket 재연결 실패:", error);
159+
if (reconnectAttemptsRef.current >= MAX_RECONNECT_ATTEMPTS) {
160+
setErrorMessage('연결이 불안정합니다. 페이지를 새로고침해주세요.');
161+
setShowErrorToast(true);
162+
}
163+
}
164+
}, RECONNECT_DELAY);
165+
} else {
166+
setErrorMessage('연결이 불안정합니다. 페이지를 새로고침해주세요.');
167+
setShowErrorToast(true);
168+
}
169+
}
170+
};
171+
};
172+
104173
useEffect(() => {
105174
if (!params.id) return;
106175
if (socketRef.current) return;
107-
// SockJS + STOMP 클라이언트 생성
108-
const socket = new SockJS(SOCKET_CONFIG.ENDPOINT);
109-
const client = Stomp.over(socket);
110-
111-
client.connect(
112-
{type: SOCKET_CONNECTION_TYPE.PUBLIC},
113-
() => {
114-
// 인원 수 토픽 구독
115-
client.subscribe(`/topic/chat.${params.id}.count`, ({ body }) => {
116-
const { count } = JSON.parse(body);
117-
setUserCount(count);
118-
});
119-
// 채팅 인원 수 초기화
120-
client.send(
121-
`/app/chat.initCount.${params.id}`,
122-
{},
123-
""
124-
);
125-
}, console.error
126-
);
127176

128-
socketRef.current = client;
177+
const initializeWebSocket = async () => {
178+
try {
179+
const client = await connectWebSocket();
180+
await subscribeToChat(client);
181+
initializeChatCount(client);
182+
setupConnectionCloseHandler(client);
183+
socketRef.current = client;
184+
} catch (error) {
185+
console.error("WebSocket 초기 연결 실패:", error);
186+
}
187+
};
188+
189+
initializeWebSocket();
129190

130191
return () => {
131-
// cleanup: 모든 구독 해제하고 연결 종료
132192
if (socketRef.current) {
133193
socketRef.current.disconnect();
134194
socketRef.current = null;
@@ -139,7 +199,7 @@ const NewsDetailPage = () => {
139199
// 채팅 에러 핸들러 추가
140200
const handleChatError = (error) => {
141201
console.log(error);
142-
setErrorMessage('채팅 서비스 연결에 실패했습니다.');
202+
setErrorMessage('채팅 서비스 연결에 실패했습니다. 페이지 새로고침 후에 다시 시도해주세요.');
143203
setShowErrorToast(true);
144204
setIsChatOpen(false);
145205
setIsChatLoading(false);

0 commit comments

Comments
 (0)