今天用 OpenCode 写一个实用的命令行 WebSocket 调试工具 ws-cli。它就像一个命令行的 Postman,可以连接任意 WebSocket 服务、发送消息、查看返回数据,还支持 JSON 格式化输出和心跳延迟检测。对于需要调试 WebSocket 接口的后端开发者来说,这个小工具比浏览器控制台方便得多。
ws 库确保环境安装了 Node.js(v14+),编辑器或终端里启动 OpenCode 即可开始。全程用自然语言对话,不用手动写一行代码。
我把最基础的需求告诉 OpenCode——能连上 WebSocket 并打印收到的消息。
我对 OpenCode 说:
> 帮我用 Node.js 写一个命令行 WebSocket 客户端 ws-cli.js。接收一个 ws 地址作为参数,连接成功后打印 'Connected',收到消息就打印出来,断开时退出进程。使用 ws 这个 npm 包。
OpenCode 做了什么:
它先判断项目还没有 package.json,自动执行 npm init -y,然后安装 ws 依赖。接着直接生成了可运行的代码:
#!/usr/bin/env node
const WebSocket = require('ws');
const url = process.argv[2];
if (!url) {
console.log('Usage: ws-cli <url>');
process.exit(1);
}
console.log(`Connecting to ${url}...`);
const ws = new WebSocket(url);
ws.on('open', () => console.log('Connected'));
ws.on('message', (data) => console.log(`Received: ${data}`));
ws.on('close', () => { console.log('Disconnected'); process.exit(0); });
ws.on('error', (err) => console.error(`Error: ${err.message}`));
不到 20 行,一个能用的 WebSocket 客户端就成型了。跑一下测试:
node ws-cli.js ws://echo.websocket.org # Connecting to ws://echo.websocket.org... # Connected
关键要点: OpenCode 不仅写了代码,还自动处理了项目初始化(npm init、安装依赖)。你不需要告诉它"先建个 package.json",它自己判断项目状态来补全缺失的步骤。
能连能收只是基础,我想要一个更灵活的参数系统。
我对 OpenCode 说:
> 给 ws-cli.js 加上命令行参数解析,支持以下选项:
> - -m "消息" 连接后自动发送这条消息
> - -j 发送时把内容包装成 {"text": "..."} 的 JSON 格式
> - -p 收到的 JSON 消息自动格式化缩进输出
> - -h 显示帮助信息(列出所有参数和示例)
OpenCode 做了什么:
它在文件顶部加了一个 parseArgs 函数,用清晰的 switch-case 解析每个参数,返回一个选项对象。然后在主逻辑里根据 opts 来决定行为——有 -m 就自动发送,有 -j 就 JSON 包装。代码从 20 行扩展到了 50 多行,但结构依然清晰。
关键要点: 你不需要描述"怎么实现"(比如"写一个 parseArgs 函数,用 switch 遍历 argv"),只需要描述"要什么效果"。OpenCode 会自己选择最合适的实现方式。
WebSocket 调试时经常要确认连接是否存活,加个心跳。
我对 OpenCode 说:
> 加一个 --ping 选项。启用后每隔 3 秒自动发一次 WebSocket ping 帧,收到 pong 后打印延迟毫秒数。断开连接时要自动清除定时器。
OpenCode 做了什么:
它在 open 回调中加了 setInterval,每次 ws.ping() 时记录时间戳,监听一次性 pong 事件计算差值。在 close 和 error 事件里用 clearInterval 清理定时器,不会出现内存泄漏:
if (opts.pingMode) {
pingInterval = setInterval(() => {
const start = Date.now();
ws.ping();
ws.once('pong', () => console.log(`💓 Pong: ${Date.now() - start}ms`));
}, 3000);
}
关键要点: 我说了"断开时要清除定时器",OpenCode 就在 close 和 error 两个地方都加了清理代码。细节交给 AI,你只负责提需求。
功能都齐了,最后打磨一下交互——图标、交互式输入、错误提示。
我对 OpenCode 说:
> 优化 ws-cli.js 的用户体验:
> 1. 不同状态的输出用 emoji 区分——连接用 🔗,成功用 ✅,收到消息用 📩,发送用 📤,错误用 ❌
> 2. 如果没有指定 -m 参数,进入交互模式,从 stdin 读取用户输入逐行发送
> 3. 连接错误时给出更友好的提示,不要只打印 stack trace
OpenCode 做了什么:
它把之前的纯文本输出替换成了 emoji,在没有 -m 时调用 process.stdin.on('data', ...) 进入交互模式,error 回调里只打印 err.message 而非完整堆栈。最终代码正好约 90 行。
#!/usr/bin/env node
const WebSocket = require('ws');
function parseArgs(args) {
if (args.length < 1 || args[0] === '-h' || args[0] === '--help') {
console.log('WebSocket CLI 调试工具\n');
console.log('用法: ws-cli <url> [选项]\n');
console.log('选项:');
console.log(' -m, --msg <text> 连接后发送的消息');
console.log(' -j, --json 以 JSON 格式发送');
console.log(' -p, --pretty 格式化接收到的 JSON');
console.log(' --ping 心跳检测 (3s 间隔)');
console.log(' -h, --help 显示帮助\n');
console.log('示例:');
console.log(' ws-cli ws://localhost:8080');
console.log(' ws-cli wss://echo.websocket.org --ping');
console.log(' ws-cli ws://localhost:8080 -m hello --json');
process.exit(0);
}
return {
url: args[0],
message: null,
jsonMode: false,
prettyMode: false,
pingMode: false,
_parse() {
for (let i = 1; i < args.length; i++) {
switch (args[i]) {
case '-m': case '--msg': this.message = args[++i]; break;
case '-j': case '--json': this.jsonMode = true; break;
case '-p': case '--pretty': this.prettyMode = true; break;
case '--ping': this.pingMode = true; break;
}
}
}
};
}
const opts = parseArgs(process.argv.slice(2));
opts._parse();
console.log(`🔗 正在连接 ${opts.url}...`);
const ws = new WebSocket(opts.url);
let pingInterval = null;
ws.on('open', () => {
console.log('✅ 已连接');
if (opts.pingMode) {
pingInterval = setInterval(() => {
const start = Date.now();
ws.ping();
ws.once('pong', () => console.log(`💓 Pong: ${Date.now() - start}ms`));
}, 3000);
console.log('💓 心跳检测已启动 (3s)');
}
if (opts.message) {
const payload = opts.jsonMode
? JSON.stringify({ text: opts.message })
: opts.message;
console.log(`📤 发送: ${payload}`);
ws.send(payload);
} else {
console.log('💬 输入消息按回车发送 (Ctrl+C 退出):');
process.stdin.on('data', (data) => {
const msg = data.toString().trim();
if (msg) {
const payload = opts.jsonMode
? JSON.stringify({ text: msg })
: msg;
ws.send(payload);
}
});
}
});
ws.on('message', (data) => {
const raw = data.toString();
try {
const parsed = JSON.parse(raw);
console.log(`📩 收到: ${
opts.prettyMode ? JSON.stringify(parsed, null, 2) : raw
}`);
} catch {
console.log(`📩 收到: ${raw}`);
}
});
ws.on('close', (code) => {
if (pingInterval) clearInterval(pingInterval);
console.log(`❌ 断开连接 (code: ${code})`);
process.exit(0);
});
ws.on('error', (err) => {
if (pingInterval) clearInterval(pingInterval);
console.error(`❌ 错误: ${err.message}`);
process.exit(1);
});
依赖安装后即可使用:
npm install ws node ws-cli.js ws://localhost:8080 --ping node ws-cli.js ws://localhost:8080 -m "hello" --json --pretty
从"帮我写一个 WebSocket 客户端"到功能完备的调试工具,实际编码环节不到 4 分钟。真正花时间的不是写代码,而是想清楚"我要什么功能"——这恰好是 AI 时代开发者应该聚焦的地方。
几点体会:
描述需求比描述实现更重要。 你不需要告诉 OpenCode"用 switch 解析参数"或"用 setInterval 做心跳",你只需要说"支持这些参数""每 3 秒发一次 ping"。OpenCode 自己选择实现路径。
渐进式迭代效率最高。 先搞一个能跑的最简版本(第一步),然后逐层加功能(第二/三/四步)。每次只提一个明确的需求,OpenCode 在已有代码基础上改,可预期、好验证。
AI 把"想法→代码"的摩擦降到了零。 哪怕你不熟悉 WebSocket 协议细节或 Node.js 事件模型,只要你能描述需求,就能拿到可运行的代码。
如果你还没试过用 AI 编程助手写工具,建议装一个 OpenCode,从一个小需求开始试。4 分钟让你体验什么叫"说话就是写代码"。