fix(workspace): normalize websocket headers for reverse proxies and show detailed disconnect reason
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m4s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m4s
This commit is contained in:
1 parent
c2ed76c6a4
commit
155d2daa02
3 files changed
+49
-7
No files matched your search
@@ -134,6 +134,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
const wsReconnectTimerRef = useRef<any>(null);
|
||||
const wsReconnectDelayRef = useRef<number>(2000);
|
||||
const [wsConnected, setWsConnected] = useState<boolean>(false);
|
||||
const [wsDisconnectReason, setWsDisconnectReason] = useState<string | null>(null);
|
||||
|
||||
// Folder state (synchronized with server)
|
||||
const [customFolders, setCustomFolders] = useState<string[]>([]);
|
||||
@@ -972,22 +973,37 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
ws.onopen = () => {
|
||||
if (!isMounted) return;
|
||||
wsReconnectDelayRef.current = 2000;
|
||||
setWsDisconnectReason(null);
|
||||
setWsConnected(true);
|
||||
api.getFolders().then(setCustomFolders).catch(() => {});
|
||||
api.getSharedFolders().then(setSharedFolders).catch(() => {});
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
ws.onclose = (evt: CloseEvent) => {
|
||||
if (!isMounted) return;
|
||||
setWsConnected(false);
|
||||
const reasonText =
|
||||
evt.reason ||
|
||||
(evt.code === 1006
|
||||
? 'Verbindung durch Firmen-Proxy oder Netzwerk getrennt (Code 1006)'
|
||||
: evt.code === 1008
|
||||
? 'Richtlinien-Verletzung durch Proxy/Firewall (Code 1008)'
|
||||
: evt.code === 1002
|
||||
? 'Protokollfehler beim Handshake (Code 1002)'
|
||||
: evt.code === 1000
|
||||
? 'Normal geschlossen (Code 1000)'
|
||||
: `Code ${evt.code}`);
|
||||
console.warn('[MindSift Workspace WS] getrennt:', evt.code, evt.reason || reasonText);
|
||||
setWsDisconnectReason(reasonText);
|
||||
clearTimeout(wsReconnectTimerRef.current);
|
||||
const delay = wsReconnectDelayRef.current;
|
||||
wsReconnectDelayRef.current = Math.min(30000, Math.round(wsReconnectDelayRef.current * 1.5));
|
||||
wsReconnectTimerRef.current = setTimeout(connect, delay);
|
||||
};
|
||||
|
||||
ws.onerror = () => {
|
||||
ws.onerror = (e) => {
|
||||
if (!isMounted) return;
|
||||
console.warn('[MindSift Workspace WS] Fehler aufgetreten:', e);
|
||||
setWsConnected(false);
|
||||
};
|
||||
|
||||
@@ -997,9 +1013,11 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
handleWsMsg(msg);
|
||||
} catch {}
|
||||
};
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (!isMounted) return;
|
||||
setWsConnected(false);
|
||||
const errText = err?.message || 'Verbindungsfehler';
|
||||
setWsDisconnectReason(errText);
|
||||
clearTimeout(wsReconnectTimerRef.current);
|
||||
const delay = wsReconnectDelayRef.current;
|
||||
wsReconnectDelayRef.current = Math.min(30000, Math.round(wsReconnectDelayRef.current * 1.5));
|
||||
@@ -1009,6 +1027,15 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
|
||||
connect();
|
||||
|
||||
// Also synchronize with global WebSocket status
|
||||
const unsubGlobalStatus = onWebSocketStatus((connected) => {
|
||||
if (!isMounted) return;
|
||||
if (connected) {
|
||||
setWsConnected(true);
|
||||
setWsDisconnectReason(null);
|
||||
}
|
||||
});
|
||||
|
||||
// Fallback: also listen for window custom event 'mindsift:ws'
|
||||
const handleGlobalCustomEvent = (e: any) => {
|
||||
if (e.detail) {
|
||||
@@ -1019,6 +1046,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
unsubGlobalStatus();
|
||||
clearTimeout(wsReconnectTimerRef.current);
|
||||
if (wsRef.current) {
|
||||
try {
|
||||
@@ -4050,7 +4078,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
title={
|
||||
wsConnected
|
||||
? 'Live synchronisiert (WebSocket online)'
|
||||
: 'Proxy/Offline-Fallback: Synchronisation über HTTP aktiv'
|
||||
: `Proxy/Offline-Fallback: Synchronisation über HTTP aktiv${wsDisconnectReason ? ` (${wsDisconnectReason})` : ''}`
|
||||
}
|
||||
>
|
||||
<Radio className={`w-3.5 h-3.5 ${wsConnected ? 'animate-pulse' : 'opacity-80'}`} />
|
||||
@@ -4090,7 +4118,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
||||
title={
|
||||
wsConnected
|
||||
? 'Live synchronisiert (WebSocket online)'
|
||||
: 'Proxy/Offline-Fallback: Synchronisation über HTTP aktiv'
|
||||
: `Proxy/Offline-Fallback: Synchronisation über HTTP aktiv${wsDisconnectReason ? ` (${wsDisconnectReason})` : ''}`
|
||||
}
|
||||
>
|
||||
<Radio className={`w-3.5 h-3.5 ${wsConnected ? 'animate-pulse' : 'opacity-80'}`} />
|
||||
|
||||
@@ -1118,8 +1118,9 @@ export function connectWebSocket(): void {
|
||||
}
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
ws.onclose = (evt: CloseEvent) => {
|
||||
activeGlobalWS = null;
|
||||
console.warn('[MindSift Global WS] Closed with code:', evt?.code, 'reason:', evt?.reason);
|
||||
notifyStatusChange(false);
|
||||
if (!manualDisconnect && getToken()) {
|
||||
clearTimeout(wsReconnectTimer);
|
||||
@@ -1131,7 +1132,8 @@ export function connectWebSocket(): void {
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = () => {
|
||||
ws.onerror = (e) => {
|
||||
console.warn('[MindSift Global WS] Error:', e);
|
||||
notifyStatusChange(false);
|
||||
try {
|
||||
ws.close();
|
||||
|
||||
@@ -1585,6 +1585,18 @@ func (s *Server) handleReorderListItems(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
func (s *Server) handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
// Some corporate proxies and reverse proxies (e.g. OpenResty/Nginx or HTTP/2 intermediaries)
|
||||
// strip or alter the Connection header (e.g. "close" or missing) while passing
|
||||
// Sec-WebSocket-Key or Upgrade: websocket. Normalize it so Gorilla Upgrader succeeds.
|
||||
if r.Header.Get("Sec-Websocket-Key") != "" {
|
||||
if !strings.Contains(strings.ToLower(r.Header.Get("Connection")), "upgrade") {
|
||||
r.Header.Set("Connection", "Upgrade")
|
||||
}
|
||||
if !strings.Contains(strings.ToLower(r.Header.Get("Upgrade")), "websocket") {
|
||||
r.Header.Set("Upgrade", "websocket")
|
||||
}
|
||||
}
|
||||
|
||||
roomID := chi.URLParam(r, "listId")
|
||||
if roomID == "" {
|
||||
roomID = chi.URLParam(r, "spaceId")
|
||||
|
||||
Reference in new issue
Block a user