fix: websocket proxy

This commit is contained in:
hamster1963 2024-11-23 17:31:00 +08:00
parent 1bda0cc3b7
commit d1558b71c4
5 changed files with 61 additions and 26 deletions

View File

@ -3,7 +3,6 @@ import { useState, useEffect, useRef, useCallback } from "react";
export interface WebSocketHook { export interface WebSocketHook {
socket: WebSocket | null; socket: WebSocket | null;
connected: boolean; connected: boolean;
onlineCount: number;
message: string | null; message: string | null;
sendMessage: (msg: string) => void; sendMessage: (msg: string) => void;
} }
@ -12,7 +11,6 @@ export default function useWebSocket(url: string): WebSocketHook {
const [socket, setSocket] = useState<WebSocket | null>(null); const [socket, setSocket] = useState<WebSocket | null>(null);
const [message, setMessage] = useState<string | null>(null); const [message, setMessage] = useState<string | null>(null);
const [connected, setConnected] = useState<boolean>(false); const [connected, setConnected] = useState<boolean>(false);
const [onlineCount, setOnlineCount] = useState<number>(0);
const socketRef = useRef<WebSocket | null>(null); const socketRef = useRef<WebSocket | null>(null);
const reconnectAttempts = useRef<number>(0); const reconnectAttempts = useRef<number>(0);
const reconnectTimeout = useRef<NodeJS.Timeout | null>(null); const reconnectTimeout = useRef<NodeJS.Timeout | null>(null);
@ -32,28 +30,37 @@ export default function useWebSocket(url: string): WebSocketHook {
ws.onmessage = (event: MessageEvent) => { ws.onmessage = (event: MessageEvent) => {
setMessage(event.data); setMessage(event.data);
const msgJson = JSON.parse(event.data);
if (msgJson.type === "live") {
setOnlineCount(msgJson.data.count);
}
}; };
ws.onerror = (error) => { ws.onerror = (error) => {
console.error("WebSocket Error:", error); console.error("WebSocket Error:", error);
// 在错误发生时主动关闭连接,触发重连
if (ws.readyState === WebSocket.OPEN) {
ws.close();
}
}; };
ws.onclose = () => { ws.onclose = () => {
setConnected(false); setConnected(false);
// 清理当前的 socket
socketRef.current = null;
if (!isUnmounted.current) { if (!isUnmounted.current) {
// Attempt to reconnect // 检查是否已经在重连中
if (reconnectAttempts.current < 5) { if (reconnectTimeout.current) {
const timeout = Math.pow(2, reconnectAttempts.current) * 1000; // Exponential backoff clearTimeout(reconnectTimeout.current);
}
// Attempt to reconnect with increased max attempts
if (reconnectAttempts.current < 10) {
const timeout = Math.min(Math.pow(2, reconnectAttempts.current) * 1000, 30000); // 最大30秒
reconnectAttempts.current += 1; reconnectAttempts.current += 1;
console.log(`Attempting to reconnect in ${timeout/1000} seconds...`);
reconnectTimeout.current = setTimeout(() => { reconnectTimeout.current = setTimeout(() => {
connect(); connect();
}, timeout); }, timeout);
} else { } else {
console.warn("Max reconnect attempts reached."); console.warn("Max reconnect attempts reached. Please refresh the page to try again.");
} }
} }
}; };
@ -85,5 +92,5 @@ export default function useWebSocket(url: string): WebSocketHook {
} }
}, []); }, []);
return { socket, message, sendMessage, connected, onlineCount }; return { socket, message, sendMessage, connected };
} }

View File

@ -0,0 +1,14 @@
import { createContext, useContext } from "react";
import { WebSocketHook } from "../hooks/use-websocket";
export const WebSocketContext = createContext<WebSocketHook | undefined>(undefined);
export const useWebSocketContext = (): WebSocketHook => {
const context = useContext(WebSocketContext);
if (!context) {
throw new Error(
"useWebSocketContext must be used within a WebSocketProvider",
);
}
return context;
};

View File

@ -1,25 +1,14 @@
import { createContext, useContext, ReactNode } from "react"; import { ReactNode } from "react";
import useWebSocket, { WebSocketHook } from "./useWebsocket"; import useWebSocket from "../hooks/use-websocket";
import { WebSocketContext } from "./websocketContext";
interface WebSocketProviderProps { interface WebSocketProviderProps {
children: ReactNode; children: ReactNode;
} }
const WebSocketContext = createContext<WebSocketHook | undefined>(undefined);
export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { export const WebSocketProvider = ({ children }: WebSocketProviderProps) => {
const ws = useWebSocket("wss://dev-next.buycoffee.top:4433/api/v1/ws/server"); const ws = useWebSocket('/api/v1/ws/server');
return ( return (
<WebSocketContext.Provider value={ws}>{children}</WebSocketContext.Provider> <WebSocketContext.Provider value={ws}>{children}</WebSocketContext.Provider>
); );
}; };
export const useWebSocketContext = (): WebSocketHook => {
const context = useContext(WebSocketContext);
if (!context) {
throw new Error(
"useWebSocketContext must be used within a WebSocketProvider",
);
}
return context;
};

View File

@ -1,4 +1,20 @@
import { useWebSocketContext } from "@/lib/websocketContext";
import { NezhaAPI } from "@/types/nezha-api";
export default function Servers() { export default function Servers() {
const { connected, message } = useWebSocketContext()
if (!connected || !message) {
return (
<p>...</p>
)
}
const nezhaWsData = JSON.parse(message) as NezhaAPI[]
console.log(nezhaWsData)
return ( return (
<div className="mx-auto w-full max-w-5xl px-4 lg:px-0"> <div className="mx-auto w-full max-w-5xl px-4 lg:px-0">
<div className="flex justify-between mb-4 mt-4 items-center"> <div className="flex justify-between mb-4 mt-4 items-center">

View File

@ -10,4 +10,13 @@ export default defineConfig({
"@": path.resolve(__dirname, "./src"), "@": path.resolve(__dirname, "./src"),
}, },
}, },
server: {
proxy: {
'/api/v1/ws': {
target: 'http://localhost:8008',
changeOrigin: true,
ws: true,
},
}
}
}); });