websocket连接失败但http正常,主因是代理未启用ws: true且目标地址非ws://协议;hmr端口冲突或csp策略限制也会导致类似错误。

WebSocket连接失败但HTTP接口正常?检查代理是否支持协议升级
Vite的vite.config.ts里用server.proxy配HTTP代理时,默认不转发WebSocket升级请求。现象是:API调用成功,但new WebSocket('ws://localhost:5173/api/ws')直接报net::ERR_CONNECTION_REFUSED或握手400错误。
根本原因在于WebSocket建立前要先发一个带Upgrade: websocket和Connection: upgrade头的HTTP请求,普通代理会忽略这些头、直接返回404或降级处理。
- 必须显式启用WebSocket代理:在proxy配置项里加
ws: true - 目标地址必须用
ws://或wss://开头(不能写http://) - 如果后端WebSocket服务跑在
ws://localhost:8080/ws,proxy应写成:server: { proxy: { '/api/ws': { target: 'ws://localhost:8080', ws: true, changeOrigin: true } } }
浏览器控制台显示“Invalid frame header”或“Close event 1006”?确认HMR端口与代理路径没冲突
Vite开发服务器自身要用WebSocket做热更新(HMR),默认复用server.port。如果你把/ws代理到了后端,但前端代码又试图连ws://localhost:5173/ws,实际连上的可能是Vite自己的HMR服务,导致协议错乱。
典型表现:页面能加载,但自定义WebSocket收不到消息,控制台反复打印Invalid frame header。
- 前端WebSocket地址不要硬写
localhost:5173,改用相对路径:new WebSocket('/api/ws') - 确保代理路径前缀(如
/api/ws)和前端连接路径完全一致,大小写、斜杠都不能错 - 检查
vite.config.ts中server.hmr.port是否被手动设成和后端WebSocket端口相同——这会导致端口争抢,建议留空让Vite自动分配
通过外网域名或内网穿透访问时无限刷新?修正HMR的WebSocket地址
当你用ngrok、cpolar等工具把localhost:5173映射成https://xxx.ngrok.io时,Vite客户端脚本仍会尝试连ws://xxx.ngrok.io:5173(而该端口未暴露),触发重连循环,页面不断刷新。
这不是代理问题,而是Vite客户端生成的HMR连接地址写死了host。
- 临时方案:修改
node_modules/vite/dist/client/client.mjs里socketHost的拼接逻辑,替换成你的穿透域名或局域网IP - 长期方案:在
vite.config.ts中用server.host和server.hmr.overlay组合控制——设host: '0.0.0.0'并配合hmr: { overlay: false }可减少干扰,但最稳的是用defineConfig注入环境变量,在client代码里动态取host - 注意:修改
node_modules后需清缓存重装,且下次vite升级会覆盖
Electron-Vite里报“Refused to connect to 'ws://...' because it violates CSP”?补全connect-src指令
Electron默认CSP策略只允许'self',连ws://localhost:3000都会被拦截,报错里明确提示connect-src未设置,回退到default-src。
不能简单关掉webSecurity,那等于放弃安全沙箱。
- 在Electron主进程创建
BrowserWindow时,用webPreferences.contextIsolation = false配合preload脚本注入meta标签(仅限开发) - 更推荐:在入口HTML的
里加(注意单引号和星号语法) - 若后端WebSocket地址固定,比如
ws://api.example.com:8080,请把ws://localhost:*替换成具体地址,避免过度开放
Vite里WebSocket的问题,八成出在“以为代理了HTTP就自动管WebSocket”,或者“没意识到HMR自己也在抢同一个协议通道”。动手前先看一眼浏览器Network面板里WebSocket连接的真实目标地址和状态码,比猜快得多。











