现象
给一个 QQ 机器人换协议端的时候,HTTP 侧一切正常:get_login_info 能返回账号和昵称,说明登录、端口、鉴权都没问题。但 WebSocket 侧一直连不上,客户端反复断开,服务端日志里只有一行 WebSocket 1006——没有原因,没有错误码,只有断。
1006 的意思是「连接异常关闭,且没有收到关闭帧」。它本身不说明任何事,只说明对面没打招呼就把线拔了。
排查
先排除网络:端口通、握手能过、TLS 无关(本地回环)。再排除鉴权顺序:HTTP 用 Bearer,WS 用 query 参数,两者本来是两套入口,容易以为是同一个。
真正的问题在配置:onebot.json 里 wsServers[].accessToken 和 httpServers[].accessToken 是两个值,我一开始只改了前者。
但改完还是 1006。直到看见数据目录里还有第二个文件——onebot_<uin>.json,同目录、同结构,名字里带账号。它是按账号区分的覆盖文件:主配置先加载,账号配置后加载,后者覆盖前者。
也就是说,我改的那个 onebot.json 一直在被覆盖。
修复
两处都改成一致的值:
"wsServers": [{ "accessToken": "<同一个值>" }],
"httpServers": [{ "accessToken": "<同一个值>" }]
改之前先备份两个文件,改完重启协议端容器。
验证
- WS 不再 1006,客户端连上后能收到事件
- HTTP 侧鉴权照旧通过
- 机器人收发消息正常,私聊与群聊都通了
遗留代价
- 重启容器会掉登录。协议端不是无状态服务,进程重启后要重新确认登录,这一步自动化不了,只能人工点。所以「改配置」这件事的成本不是改的那一下,而是之后要盯着登录态。
- 同目录存在覆盖文件这件事没有任何提示。配置项写在两个文件里,缺失的那个不报错,只是静默生效。以后遇到「改了没用」,先
ls一遍目录,看有没有带账号后缀的副本。 - 1006 这个错误码本身不携带信息,别再花时间从它身上找原因,直接从「谁在什么时候断的」反推。
一句话总结:不是网络问题,不是鉴权顺序问题,是两个配置文件里同名的一项,后加载的那个赢了。
—— 白幻