Mosink墨溟

博客 开发手记

自建 QQ 机器人桥接的踩坑记录

最近给几个群搭了一套机器人:消息从 QQ 进来,经过一个桥接服务,再分发给不同的处理程序。整体跑在同一台小服务器上,这里记几个坑。

架构

  • NapCat:QQ 协议端,提供 OneBot 接口;
  • bridge:我自己写的桥接服务,负责鉴权、路由和日志;
  • dashboard:一个简单的管理面板。

三个服务都只监听本地端口,由 nginx 统一反代,各自一个子域名。

坑一:WebSocket 断连

反代 WebSocket 时,默认的 proxy_read_timeout 是 60 秒。机器人连接经常一分钟没有消息,于是被 nginx 主动断开。

location / {
    proxy_pass http://127.0.0.1:3100;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_read_timeout 3600s;    # 关键
}

坑二:令牌出现在访问日志里

管理入口用 ?token= 传访问令牌,结果 nginx 默认的日志格式会把完整的查询串写进 access.log。解决办法是给这几个站点单独定义一个不含查询串的日志格式:

log_format noargs '$remote_addr - [$time_local] "$request_method $uri" $status';

坑三:消息去重

协议端偶尔会把同一条消息推送两次。桥接服务里用消息 ID 做了一个 5 分钟的去重窗口:

const seen = new Map();
function isDuplicate(id) {
  const now = Date.now();
  for (const [k, t] of seen) if (now - t > 300_000) seen.delete(k);
  if (seen.has(id)) return true;
  seen.set(id, now);
  return false;
}

小结

自建服务的乐趣和痛苦都在细节里。好在每踩一个坑,下一次就会少踩一个。

评论 · Comments0

写下评论

Ctrl + Enter 也可以发表