Webpack dev server启用HMR时如何正确代理WebSocket请求
Webpack Dev Server WebSocket代理报错
ERR_STREAM_WRITE_AFTER_END问题处理 问题场景
- 技术栈:基于Webpack 5构建React前端项目,后端作为独立进程运行,通过Webpack Dev Server(简称WDS)将前端请求代理到后端服务
- 异常现象:普通HTTP API请求代理正常,添加带
ws: true参数的WebSocket代理规则后,本地访问页面时控制台每秒重复抛出流写入错误;即使移除客户端业务WebSocket连接代码,错误依然存在 - 后续排查:修改业务WebSocket代理路径为
/websocket规避路径冲突后,出现WebSocket连接失败问题;经原生静态页直连测试,后端WebSocket服务本身运行正常,判定异常来自WDS配置
初始报错日志
<i> [webpack-dev-server] [HPM] Upgrading to WebSocket <e> [webpack-dev-server] [HPM] WebSocket error: Error [ERR_STREAM_WRITE_AFTER_END]: write after end <e> at new NodeError (node:internal/errors:372:5) <e> at _write (node:internal/streams/writable:319:11) <e> at Socket.Writable.write (node:internal/streams/writable:334:10) <e> at Sender.sendFrame (C:\code\line-up\line-up-client\node_modules\ws\lib\sender.js:469:20) <e> at Sender.close (C:\code\line-up\line-up-client\node_modules\ws\lib\sender.js:197:12) <e> at WebSocket.close (C:\code\line-up\line-up-client\node_modules\ws\lib\websocket.js:300:18) <e> at Receiver.receiverOnConclude (C:\code\line-up\line-up-client\node_modules\ws\lib\websocket.js:1114:18) <e> at Receiver.emit (node:events:527:28) <e> at Receiver.controlMessage (C:\code\line-up\line-up-client\node_modules\ws\lib\receiver.js:582:14) <e> at Receiver.getData (C:\code\line-up\line-up-client\node_modules\ws\lib\receiver.js:429:42) { <e> code: 'ERR_STREAM_WRITE_AFTER_END' <e> }
初始配置与环境信息
初始代理配置
proxy: { '/api/*': { target: 'http://localhost:5150', pathRewrite: { '^/api': '' }, }, '/ws': { target: 'ws://localhost:5150', ws: true, } },
服务信息
- 后端HTTP服务监听地址:
http://localhost:5150 - 后端WebSocket端点:
localhost:5150/ws
依赖版本
"webpack": "^5.72.1", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.9.0"
已尝试无效方案
- 将
/ws代理的target改为http协议 - 将target直接指向
/ws路径 - 为所有代理规则添加
ws: true配置 - 调整多组配置组合均未解决问题
解决方案
根因说明
- 初始循环报错:自定义
/ws代理路径和WDS内置热更新(HMR)的默认WebSocket路径完全重合,代理规则拦截了HMR本身的WebSocket连接,导致连接反复断开重连抛出流写入错误。 - 路径修改后连接失败:WDS 4.x底层依赖
http-proxy-middleware处理WebSocket代理时,默认未正确转发Origin头,且缺少对内置HMR连接的跳过逻辑。
可用代理配置
直接替换devServer中的proxy配置即可:
proxy: { '/api/*': { target: 'http://localhost:5150', pathRewrite: { '^/api': '' }, }, '/websocket': { target: 'http://localhost:5150', ws: true, changeOrigin: true, bypass: (req) => { // 跳过WDS自身的HMR WebSocket请求,避免被当前规则拦截 if (req.headers.upgrade && req.url.startsWith('/ws')) { return req.url; } } } },
极端场景兼容配置
如果上述配置仍存在连接异常,显式指定WDS客户端的HMR WebSocket地址,彻底和业务WebSocket路径隔离:
devServer: { // 其余原有配置保持不变 client: { // 端口替换为本地WDS实际运行的端口,默认是8080 webSocketURL: 'ws://localhost:8080/ws' } }
验证方式
- 重启WDS后控制台不再循环抛出
ERR_STREAM_WRITE_AFTER_END错误 - 客户端业务代码通过
new WebSocket(ws://${window.location.host}/websocket)发起连接,即可正常对接后端WebSocket服务
内容的提问来源于stack exchange,提问作者tvandinther
相关产品推荐
相关产品推荐

