创建WebSocket代理连接浏览器与Docker容器的数据流转问题排查
Docker容器WebSocket双向代理修复方案
你的代码无法实现双向数据流转的核心问题是向Docker exec流写入数据的方式错误:你用了stream.emit("data", msg)来模拟数据输入,但Docker的Hijack流需要通过stream.write()方法主动写入数据到容器标准输入。另外,还需要处理流的错误、WebSocket连接关闭后的资源清理,以及二进制数据的正确传输。
修正后的完整代码如下:
wss.on("connection", async (ws) => { const container = docker.getContainer("76941c597e89"); console.log("client connected"); try { const exec = await container.exec({ Cmd: ["/bin/sh"], AttachStdin: true, AttachStdout: true, AttachStderr: true, // 建议同时绑定标准错误输出 User: "root", }); const stream = await new Promise((resolve, reject) => { exec.start({ Tty: true, hijack: true }, (err, stream) => { if (err) return reject(err); resolve(stream); }); }); // 容器输出转发到WebSocket客户端 stream.on("data", (data) => { // Tty模式下直接发送二进制数据,避免转字符串乱码 ws.send(data); }); // WebSocket客户端输入转发到容器 ws.on("message", (msg) => { // 如果是字符串,转成Buffer再写入;二进制数据直接写入 const inputData = typeof msg === "string" ? Buffer.from(msg) : msg; stream.write(inputData); }); // 处理流错误 stream.on("error", (err) => { console.error("exec stream error:", err); ws.close(1011, "Exec stream error"); }); // 流关闭时断开WebSocket stream.on("end", () => { console.log("exec stream closed"); ws.close(1000, "Exec session ended"); }); // WebSocket关闭时清理exec流 ws.on("close", () => { console.log("client disconnected"); stream.destroy(); // 销毁exec流,释放资源 }); } catch (err) { console.error("exec setup failed:", err); ws.close(1011, "Failed to setup exec session"); } });
关键修复点说明
- 数据写入方式修正:将
stream.emit("data", msg)替换为stream.write(inputData),这是Docker Hijack流接受输入的正确方式。 - 二进制数据处理:Tty模式下容器输出是二进制格式,直接发送二进制数据到WebSocket避免字符编码乱码;客户端输入也统一转成Buffer后写入。
- 错误与资源清理:添加了流错误监听、流结束监听,以及WebSocket关闭时销毁exec流,防止资源泄漏。
- 标准错误绑定:新增
AttachStderr: true,确保容器的错误输出也能转发到客户端。
内容的提问来源于stack exchange,提问作者Anish
相关产品推荐
相关产品推荐

