VNC WebSocket 연결 문제 - 브라우저 보안 정책으로 인한 미해결 상태
WebSocket 1006 오류로 인해 브라우저에서 VNC 연결 실패 - 서버 환경에서는 연결 가능하나 브라우저 보안 정책으로 차단 - 역방향 프록시 솔루션 문서화 완료 - 추후 nginx 프록시 구현 필요 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -74,10 +74,31 @@
|
||||
|
||||
// This function is called when we are disconnected
|
||||
function disconnectedFromServer(e) {
|
||||
console.log('🔌 VNC 연결 해제 상세 정보:', e.detail);
|
||||
|
||||
if (e.detail.clean) {
|
||||
status("Disconnected");
|
||||
status("연결이 정상적으로 종료되었습니다");
|
||||
} else {
|
||||
status("Something went wrong, connection is closed");
|
||||
const reason = e.detail.reason || 'Unknown';
|
||||
status(`연결 실패: ${reason} (Code: ${e.detail.code || 'Unknown'})`);
|
||||
console.error('❌ VNC 연결 실패 상세:', {
|
||||
code: e.detail.code,
|
||||
reason: e.detail.reason,
|
||||
wasClean: e.detail.clean
|
||||
});
|
||||
|
||||
// WebSocket 에러 코드별 메시지
|
||||
const errorMessages = {
|
||||
1006: 'WebSocket 서버에 연결할 수 없습니다. VM이 실행중인지 확인하세요.',
|
||||
1000: '정상적으로 연결이 종료되었습니다.',
|
||||
1002: '프로토콜 오류가 발생했습니다.',
|
||||
1003: '지원하지 않는 데이터를 받았습니다.',
|
||||
1009: '메시지가 너무 큽니다.',
|
||||
1011: '서버에서 예상치 못한 오류가 발생했습니다.'
|
||||
};
|
||||
|
||||
const userFriendlyMessage = errorMessages[e.detail.code] || `알 수 없는 오류 (코드: ${e.detail.code})`;
|
||||
status(`❌ ${userFriendlyMessage}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,22 +211,103 @@
|
||||
console.log('WebSocket URL:', websocketUrl);
|
||||
console.log('VNC Password:', vncPassword);
|
||||
|
||||
status("Connecting");
|
||||
// WebSocket URL 유효성 검사
|
||||
function validateWebSocketUrl(url) {
|
||||
if (!url || typeof url !== 'string') {
|
||||
console.error('❌ WebSocket URL이 비어있습니다');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!url.startsWith('wss://') && !url.startsWith('ws://')) {
|
||||
console.error('❌ 올바르지 않은 WebSocket URL 프로토콜:', url);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('✅ WebSocket URL 유효성 검사 통과');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creating a new RFB object will start a new connection
|
||||
rfb = new RFB(document.getElementById('screen'), websocketUrl,
|
||||
{ credentials: { password: vncPassword } });
|
||||
// VNC 연결 함수
|
||||
function connectToVNC() {
|
||||
if (!validateWebSocketUrl(websocketUrl)) {
|
||||
status("❌ 잘못된 WebSocket URL입니다");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vncPassword || vncPassword.trim() === '') {
|
||||
status("❌ VNC 패스워드가 없습니다");
|
||||
return;
|
||||
}
|
||||
|
||||
status("Connecting to VM...");
|
||||
console.log('🔄 VNC 연결 시도 시작...');
|
||||
|
||||
// Add listeners to important events from the RFB module
|
||||
rfb.addEventListener("connect", connectedToServer);
|
||||
rfb.addEventListener("disconnect", disconnectedFromServer);
|
||||
rfb.addEventListener("credentialsrequired", credentialsAreRequired);
|
||||
rfb.addEventListener("desktopname", updateDesktopName);
|
||||
rfb.addEventListener("securityfailure", onSecurityFailure);
|
||||
try {
|
||||
// WebSocket 연결 직접 테스트
|
||||
console.log('🧪 WebSocket 연결 직접 테스트...');
|
||||
const testWS = new WebSocket(websocketUrl);
|
||||
|
||||
testWS.onopen = function(event) {
|
||||
console.log('✅ WebSocket 연결 테스트 성공');
|
||||
testWS.close();
|
||||
|
||||
// WebSocket이 연결되면 RFB 객체 생성
|
||||
createRFBConnection();
|
||||
};
|
||||
|
||||
testWS.onerror = function(error) {
|
||||
console.error('❌ WebSocket 연결 테스트 실패:', error);
|
||||
status('❌ WebSocket 서버에 연결할 수 없습니다');
|
||||
|
||||
// 대안: 티켓 새로고침 시도
|
||||
setTimeout(() => {
|
||||
status('🔄 새 티켓으로 재시도 중...');
|
||||
refreshVNCTicket();
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
testWS.onclose = function(event) {
|
||||
console.log('🔌 WebSocket 테스트 연결 종료:', event.code, event.reason);
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ WebSocket 테스트 실패:', error);
|
||||
status(`❌ 연결 초기화 실패: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// RFB 연결 생성 함수
|
||||
function createRFBConnection() {
|
||||
try {
|
||||
console.log('🔄 RFB 객체 생성 시작...');
|
||||
|
||||
// Creating a new RFB object will start a new connection
|
||||
rfb = new RFB(document.getElementById('screen'), websocketUrl,
|
||||
{ credentials: { password: vncPassword } });
|
||||
|
||||
console.log('✅ RFB 객체 생성 완료');
|
||||
|
||||
// Add listeners to important events from the RFB module
|
||||
rfb.addEventListener("connect", connectedToServer);
|
||||
rfb.addEventListener("disconnect", disconnectedFromServer);
|
||||
rfb.addEventListener("credentialsrequired", credentialsAreRequired);
|
||||
rfb.addEventListener("desktopname", updateDesktopName);
|
||||
rfb.addEventListener("securityfailure", onSecurityFailure);
|
||||
|
||||
// Set parameters that can be changed on an active connection
|
||||
rfb.viewOnly = false;
|
||||
rfb.scaleViewport = true;
|
||||
// Set parameters that can be changed on an active connection
|
||||
rfb.viewOnly = false;
|
||||
rfb.scaleViewport = true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ RFB 객체 생성 실패:', error);
|
||||
status(`❌ VNC 클라이언트 초기화 실패: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 연결 시작
|
||||
connectToVNC();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user