You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron中Socket.IO客户端未先启动Flask服务器时无法连接问题

Electron中Socket.IO客户端连接Flask-SocketIO服务器的CORS异常问题

我在Electron应用中运行Socket.IO客户端,连接使用flask_socketio的Flask服务器。先启动服务器再启动客户端时所有功能正常,但先启动客户端再启动服务器,Socket始终无法连接,持续出现CORS错误。

客户端代码

export function useSocket(onProgress: (progress: number) => void) {
  const socket = useRef<Socket>();

  const cleanup = useCallback(() => {
    socket.current?.off('connect');
    socket.current?.off('connect_error');
    socket.current?.off('error');
    socket.current?.off(SocketMessage.PROGRESS);
    socket.current?.disconnect();
  }, []);

  const createSocket = useCallback(() => {
    socket.current = io('http://127.0.0.1:5000', { forceNew: true });
    socket.current.on('connect', () => console.log('Connected to Flask.'));
    socket.current.on('connect_error', (err: Error) => {
      console.error('CONNECTION ERROR', err);
      cleanup();
      setTimeout(() => {
        createSocket();
      }, 1000);
    });
    socket.current.on('error', (err: Error) => console.error(err));
    socket.current.on(SocketMessage.PROGRESS, onProgress);
  }, []);

  useEffect(() => {
    createSocket();
    return cleanup;
  }, [cleanup]);
}

Flask端代码

socketio = SocketIO(
    app, cors_allowed_origins="*", async_mode="eventlet", engineio_logger=True
)
socketio.run(app, port=5000, debug=True)

错误信息

app_window:1 Access to XMLHttpRequest at 'http://127.0.0.1:5000/socket.io/?EIO=4&transport=polling&t=OCf9ogr' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

问题分析

这既不是Electron缓存问题,也不是单纯的Flask配置问题,核心是Socket.IO客户端手动重试逻辑的缺陷,加上Chromium内核对失败请求的CORS错误缓存:

  • 客户端先启动时,服务器未就绪,请求会收到底层TCP连接失败(而非带CORS头的HTTP响应),Chromium会将此标记为「无CORS允许头」的错误并缓存。
  • 手动重试逻辑中,旧Socket实例清理不彻底,forceNew: true可能未完全创建新实例,后续重试时浏览器复用之前的错误缓存,即使服务器已启动也触发CORS拦截。

解决方案

1. 优化实例清理逻辑

修改cleanup函数,彻底清除旧Socket实例,避免残留:

const cleanup = useCallback(() => {
  if (socket.current) {
    socket.current.off('connect');
    socket.current.off('connect_error');
    socket.current.off('error');
    socket.current.off(SocketMessage.PROGRESS);
    socket.current.disconnect();
    socket.current = null; // 彻底销毁旧实例
  }
}, []);

2. 改用Socket.IO内置重连机制

Socket.IO客户端自带成熟的自动重连功能,比手动实现更可靠,移除手动重试逻辑:

const createSocket = useCallback(() => {
  socket.current = io('http://127.0.0.1:5000', {
    forceNew: true,
    reconnection: true,
    reconnectionAttempts: Infinity, // 无限重试
    reconnectionDelay: 1000 // 重试间隔1秒
  });
  socket.current.on('connect', () => console.log('Connected to Flask.'));
  socket.current.on('connect_error', (err: Error) => {
    console.error('CONNECTION ERROR', err);
  });
  socket.current.on('error', (err: Error) => console.error(err));
  socket.current.on(SocketMessage.PROGRESS, onProgress);
}, [onProgress]); // 添加onProgress依赖,避免闭包失效

3. 调整Flask-SocketIO的CORS配置

将通配符*改为Electron应用的具体Origin,避免通配符在某些场景下的兼容性问题:

socketio = SocketIO(
    app, cors_allowed_origins="http://localhost:3000", async_mode="eventlet", engineio_logger=True
)

4. 检查Electron窗口配置

确保BrowserWindow的webPreferences没有禁用安全策略或异常缓存:

const mainWindow = new BrowserWindow({
  webPreferences: {
    webSecurity: true, // 保持默认安全策略
    cache: false // 禁用缓存避免错误残留
  }
});

内容的提问来源于stack exchange,提问作者CaptainStiggz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 15:35:29