Vite应用遇“WebSocket连接建立前已关闭”错误,调试无果求解决方案
解决Vite中Socket.io连接报错“WebSocket is closed before the connection is established”
问题重现
运行Vite React应用时,控制台持续输出错误:WebSocket is closed before the connection is established,尝试常规方法后仍无法解决,连接初始化代码如下:
import useSocket from "@/utils/socket"; import { createContext, useCallback, useEffect, useRef, useState } from "react"; import { AppContext } from "./context"; import { useCookies } from "react-cookie"; import { io } from "socket.io-client"; import { Socket } from "socket.io-client"; import { DefaultEventsMap } from "socket.io"; export const ContextProvider = ({children}) => { const [cookies] = useCookies(['token']) const [isConnected, setIsConnected] = useState(false) const [socket, setSocket] = useState<Socket<DefaultEventsMap, DefaultEventsMap> | null>(null) const [onlineCount, setOnlineCount] = useState(0) useEffect(() => { let newSocket: Socket<DefaultEventsMap, DefaultEventsMap> | null = null; if (cookies.token) { console.log(cookies.token) newSocket = io({ auth: cookies.token, reconnection: true, // Enables automatic reconnection reconnectionAttempts: 5, // Number of retry attempts reconnectionDelay: 1000, }); console.log("connect") newSocket.on("connect", () => { console.log("Socket connected") setIsConnected(true) setSocket(newSocket) }) console.log("connected") newSocket.on("connect_error", (error) => { console.error("Connection Error:", error.message); }); newSocket.on('disconnect', (reason) => { console.log("Socket disconnected", reason) setIsConnected(false) setSocket(null) }); return () => { if(newSocket) { newSocket.disconnect() } } } }, [cookies.token]) const contextValue = {socket} return ( <AppContext.Provider value={contextValue}> {children} </AppContext.Provider> ) }
排查与修复方案
1. 明确Socket.io服务端地址
当前代码中io()未传入服务端URL,Socket.io客户端会默认连接当前页面的域名端口,但Vite开发服务器和Socket.io服务端大概率不在同一地址,直接导致连接失败。
修改方式:在io()中传入服务端完整地址,同时修正auth参数格式(服务端通常期望接收对象格式的认证信息):
newSocket = io('http://localhost:3001', { // 替换为你的Socket.io服务端实际地址 auth: { token: cookies.token }, reconnection: true, reconnectionAttempts: 5, reconnectionDelay: 1000, });
2. 配置Vite开发服务器代理
如果Socket.io服务端和Vite开发服务器跨域,必须在vite.config.ts中配置代理,避免跨域策略阻断WebSocket连接:
export default defineConfig({ server: { proxy: { '/socket.io': { target: 'http://localhost:3001', // 服务端地址 ws: true, // 启用WebSocket代理 changeOrigin: true, }, }, }, });
配置完成后,客户端可使用相对路径io('/'),由Vite自动转发请求到服务端。
3. 优化Socket实例管理
原代码用useState保存socket实例,连接重连时可能触发不必要的状态更新。改用useRef保存实例,避免重复创建和状态异常:
const socketRef = useRef<Socket<DefaultEventsMap, DefaultEventsMap> | null>(null); useEffect(() => { if (cookies.token) { socketRef.current = io('http://localhost:3001', { auth: { token: cookies.token }, reconnection: true, reconnectionAttempts: 5, reconnectionDelay: 1000, }); socketRef.current.on("connect", () => { console.log("Socket connected"); setIsConnected(true); }); socketRef.current.on("connect_error", (error) => { console.error("Connection Error:", error.message); }); socketRef.current.on('disconnect', (reason) => { console.log("Socket disconnected", reason); setIsConnected(false); }); return () => { socketRef.current?.disconnect(); socketRef.current = null; }; } }, [cookies.token]); // 上下文值使用ref的current实例 const contextValue = { socket: socketRef.current };
4. 检查服务端认证逻辑
服务端若无法正确解析客户端传入的token,会直接关闭连接触发该错误。在服务端添加日志确认认证信息接收情况:
// 服务端示例代码 io.on('connection', (socket) => { const token = socket.handshake.auth.token; console.log('Received token:', token); // 执行token验证逻辑 if (!validateToken(token)) { socket.disconnect(true); // 认证失败强制断开 return; } // 后续业务逻辑 });
5. 排查浏览器环境限制
- 确保应用通过
http://或https://协议访问,避免file://协议下的WebSocket限制; - 暂时禁用浏览器的广告拦截、隐私保护类插件,排查是否有插件阻断了WebSocket连接。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

