Skip to content

KarinJS/karin-plugin-adapter-qqbot

Repository files navigation

@karinjs/adapter-qqbot

QQ机器人适配器插件,为 Karin 框架提供 QQ 机器人支持。

功能特性

  • ✅ 支持 QQ 群聊消息收发
  • ✅ 支持 QQ 好友消息收发
  • ✅ 支持 QQ 频道消息收发
  • ✅ 支持 WebSocket 和 Webhook 两种连接方式
  • ✅ 支持多种 Markdown 模板(原生、图文模板、纯文模板)
  • ✅ 支持沙盒环境和正式环境
  • ✅ 完整的 TypeScript 类型定义
  • ✅ 自动消息签名验证

安装

使用 pnpm(推荐)

pnpm add @karinjs/adapter-qqbot -w

使用 npm

npm install @karinjs/adapter-qqbot

使用 yarn

yarn add @karinjs/adapter-qqbot

快速开始

前置要求

  • 已安装并配置好 Karin 框架
  • Node.js >= 16
  • 有QQ开放平台的机器人应用

5分钟快速配置

  1. 安装插件

    pnpm add @karinjs/adapter-qqbot -w
  2. 获取机器人信息

    • 访问 QQ开放平台
    • 创建机器人应用,获取 AppID 和 Secret
  3. 创建配置

    [
      {
        "appId": "你的AppID",
        "secret": "你的Secret",
        "event": { "type": 1 }
      }
    ]
  4. 配置回调地址

    • 在QQ开放平台设置统一回调地址:https://你的域名/qqbot/webhook
    • 必须使用HTTPS协议,端口必须为443(默认HTTPS端口)
    • 该地址接收所有事件:群聊、C2C私聊、频道消息等
  5. 启动服务

    npm start

完成!现在可以邀请机器人到群聊测试了。

详细配置指南

第一步:获取机器人凭证

  1. 访问 QQ开放平台
  2. 登录并创建新的机器人应用
  3. 获取 AppIDSecret
  4. 记录这些信息,后续配置需要用到

第二步:创建配置文件

配置文件位置:@karinjs/@karinjs-adapter-qqbot/config/config.json

如果文件不存在,插件会自动创建一个空的配置文件。

第三步:基本配置

最简配置示例

[
  {
    "appId": "你的机器人AppID",
    "secret": "你的机器人Secret"
  }
]

完整配置示例

[
  {
    "appId": "你的机器人AppID",
    "secret": "你的机器人Secret",
    "prodApi": "https://api.sgroup.qq.com",
    "sandboxApi": "https://sandbox.api.sgroup.qq.com",
    "tokenApi": "",
    "sandbox": false,
    "qqEnable": true,
    "guildEnable": true,
    "guildMode": 0,
    "exclude": [],
    "regex": [
      {
        "reg": "^/",
        "rep": "#"
      }
    ],
    "markdown": {
      "mode": 0,
      "id": "",
      "kv": [
        "text_start",
        "img_dec", 
        "img_url",
        "text_end"
      ]
    },
    "event": {
      "type": 1,
      "wsUrl": "",
      "wsToken": ""
    }
  }
]

第四步:选择事件接收方式

方式一:Webhook(推荐)

适用场景: 有公网IP或域名的服务器

  1. 在配置文件中设置:
{
  "event": {
    "type": 1
  }
}
  1. 在QQ开放平台配置回调地址:
    • 回调地址格式:https://你的域名/qqbot/webhook
    • 例如:https://your-domain.com/qqbot/webhook
    • ⚠️ 重要限制:
      • 必须使用 HTTPS 协议
      • 端口必须为 443(标准HTTPS端口)
      • 不支持自定义端口(如:8080、:3000等)

重要说明: 这是统一的回调地址,QQ开放平台会将所有配置的事件类型(群聊、C2C私聊、频道消息等)都发送到这个地址。您不需要为不同的消息类型配置不同的回调地址。

方式二:WebSocket

适用场景: 内网环境,需要通过中转服务连接

  1. 在配置文件中设置:
{
  "event": {
    "type": 2,
    "wsUrl": "wss://your-websocket-server/ws",
    "wsToken": "你的ws认证token"
  }
}

第五步:反向代理配置(重要)

为什么需要反向代理?

QQ开放平台对Webhook回调地址有严格要求:

  • 必须使用HTTPS协议(不支持HTTP)
  • 端口必须为443(标准HTTPS端口,不支持自定义端口)
  • 必须有有效的SSL证书

如果你的Karin服务运行在:

  • 内网服务器(如家用电脑、局域网服务器)
  • 云服务器的内网端口(如3000端口)
  • Docker容器内部

就需要通过反向代理将内网服务暴露到公网的443端口,并配置SSL证书。

反向代理的目标

反向代理要代理的地址: http://127.0.0.1:3000/qqbot/webhook

这是Karin QQBot适配器监听的统一webhook接收地址,用于接收所有类型的QQ机器人事件,包括:

  • 群聊消息(GROUP_AT_MESSAGE_CREATE)
  • C2C私聊消息(C2C_MESSAGE_CREATE)
  • 频道消息(GUILD_MESSAGE_CREATE)
  • 频道私信(DIRECT_MESSAGE_CREATE)
  • 其他机器人事件

QQ开放平台会将所有配置的事件都发送到这个统一的回调地址,然后由适配器内部根据事件类型进行分发处理。

方案一:Nginx 反向代理(推荐)

1. 安装Nginx

# Ubuntu/Debian
sudo apt update && sudo apt install nginx

# CentOS/RHEL
sudo yum install nginx

2. 创建配置文件

创建 /etc/nginx/sites-available/karin-qqbot

server {
    listen 80;
    server_name your-domain.com;  # 替换为你的域名或公网IP
    
    # QQ机器人webhook接收地址
    location /qqbot/webhook {
        # 代理到本地Karin服务
        proxy_pass http://127.0.0.1:3000/qqbot/webhook;
        
        # 必要的代理头设置
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 关键配置:保持原始请求体用于签名验证
        proxy_buffering off;
        proxy_request_buffering off;
        proxy_read_timeout 300;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
    }
    
    # 可选:为Karin的其他功能添加代理
    location /karin/ {
        proxy_pass http://127.0.0.1:3000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

获取免费SSL证书(Let's Encrypt):

# 1. 安装certbot
sudo apt update
sudo apt install certbot python3-certbot-nginx

# 2. 获取SSL证书(自动配置Nginx)
sudo certbot --nginx -d your-domain.com

# 3. 测试自动续期
sudo certbot renew --dry-run

# 4. 设置自动续期(可选)
sudo crontab -e
# 添加以下行:
# 0 12 * * * /usr/bin/certbot renew --quiet

手动配置SSL证书:

如果你有其他SSL证书提供商的证书,按以下格式配置:

ssl_certificate /path/to/your/certificate.crt;      # 证书文件
ssl_certificate_key /path/to/your/private.key;     # 私钥文件

3. 启用配置

# 创建软链接启用站点
sudo ln -s /etc/nginx/sites-available/karin-qqbot /etc/nginx/sites-enabled/

# 测试配置文件语法
sudo nginx -t

# 重载配置
sudo systemctl reload nginx

# 确保Nginx开机自启
sudo systemctl enable nginx

4. 配置HTTPS(必需)

⚠️ 重要: QQ开放平台强制要求使用HTTPS协议和443端口,以下配置是必需的,不是可选的。

server {
    listen 443 ssl http2;
    server_name your-domain.com;
    
    # SSL证书配置(使用Let's Encrypt免费证书)
    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
    
    # 如果没有SSL证书,可以使用以下命令获取Let's Encrypt免费证书:
    # sudo apt install certbot python3-certbot-nginx
    # sudo certbot --nginx -d your-domain.com
    
    # SSL优化配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
    ssl_prefer_server_ciphers on;
    
    location /qqbot/webhook {
        proxy_pass http://127.0.0.1:3000/qqbot/webhook;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 保持原始请求体
        proxy_buffering off;
        proxy_request_buffering off;
    }
}

# HTTP自动跳转HTTPS(推荐配置)
server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$server_name$request_uri;
}

方案二:宝塔面板配置

1. 创建网站

  • 域名:填写你的域名
  • 根目录:可以是任意目录(不会用到)

2. 配置SSL证书(必需)

  • 进入网站设置 → SSL
  • 申请Let's Encrypt免费证书或上传自有证书
  • 开启"强制HTTPS"

3. 添加反向代理

有两种配置方式,选择其一:

方式一:代理整个域名到Karin服务

  • 代理名称: Karin Service
  • 目标URL: http://127.0.0.1:3000
  • 发送域名: $host
  • 代理目录: /

方式二:只代理webhook路径(推荐)

  • 代理名称: QQBot Webhook
  • 目标URL: http://127.0.0.1:3000/qqbot/webhook
  • 发送域名: $host
  • 代理目录: /qqbot/webhook

推荐使用方式一,这样整个域名都会指向您的Karin服务,QQ开放平台访问 https://your-domain.com/qqbot/webhook 时会被代理到 http://127.0.0.1:3000/qqbot/webhook

4. 高级设置 添加以下配置到反向代理的配置文件中:

proxy_buffering off;
proxy_request_buffering off;

重要提醒: 确保网站已启用HTTPS并强制跳转,QQ开放平台只接受HTTPS协议的回调地址。

方案三:Caddy 服务器

1. 安装Caddy

# 参考官方文档安装Caddy

2. 创建Caddyfile

your-domain.com {
    reverse_proxy /qqbot/webhook/* 127.0.0.1:3000
    
    # 自动HTTPS
    tls {
        on_demand
    }
}

方案四:Cloudflare Tunnel(内网穿透)

适用场景: 没有公网IP,通过Cloudflare暴露服务

1. 安装cloudflared

# 下载并安装cloudflared
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb

2. 登录Cloudflare

cloudflared tunnel login

3. 创建隧道

cloudflared tunnel create karin-qqbot

4. 配置DNS

cloudflared tunnel route dns karin-qqbot your-subdomain.your-domain.com

5. 运行隧道

cloudflared tunnel run --url http://localhost:3000 karin-qqbot

方案五:frp 内网穿透

适用场景: 使用自建或第三方frp服务

客户端配置 (frpc.ini):

[common]
server_addr = your-frp-server.com
server_port = 7000
token = your_token

[karin-qqbot]
type = http
local_ip = 127.0.0.1
local_port = 3000
custom_domains = your-domain.com

第六步:QQ开放平台回调地址要求

官方限制条件

QQ开放平台对Webhook回调地址有以下强制要求

要求项 限制 说明
协议 必须HTTPS 不支持HTTP协议
端口 必须443 不支持自定义端口(如:8080、:3000等)
SSL证书 必须有效 需要被浏览器信任的证书
域名 必须有域名 不支持IP地址直接访问
响应时间 3秒内 超时会重试

正确的回调地址格式

正确格式:

  • https://your-domain.com/qqbot/webhook
  • https://bot.your-company.com/qqbot/webhook

错误格式:

  • http://your-domain.com/qqbot/webhook (不支持HTTP)
  • https://your-domain.com:3000/qqbot/webhook (不支持自定义端口)
  • https://123.456.789.10/qqbot/webhook (不支持IP地址)

第七步:域名和防火墙配置

域名解析配置

确保域名正确解析到你的服务器:

# 检查域名解析
nslookup your-domain.com
dig your-domain.com

防火墙配置

Ubuntu/Debian (ufw):

# 开放HTTP和HTTPS端口
sudo ufw allow 80
sudo ufw allow 443

# 如果直接暴露端口
sudo ufw allow 3000

CentOS/RHEL (firewalld):

# 开放端口
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload

云服务器安全组:

  • 阿里云:安全组规则添加入方向 80、443 端口
  • 腾讯云:防火墙规则添加入站 80、443 端口
  • AWS:Security Group 添加 HTTP、HTTPS 规则

第九步:配置参数说明

参数 说明 默认值
appId 机器人ID(必填) ""
secret 机器人密钥(必填) ""
sandbox 是否使用沙盒环境 false
qqEnable 是否启用QQ场景 true
guildEnable 是否启用频道场景 true
guildMode 频道模式(0公域,1私域) 0
event.type 事件接收方式(0关闭,1webhook,2ws) 0

Markdown 模式说明

模式 说明 适用场景
0 直接发送 简单文本和图片消息
1 原生Markdown 需要富文本格式
3 旧图文模板 复杂图文混排
4 纯文模板 多段文本消息
5 自定义处理 完全自定义逻辑

支持的事件类型

QQ机器人适配器通过统一的webhook地址接收以下事件类型:

事件类型 说明 处理函数
GROUP_AT_MESSAGE_CREATE 群聊@机器人消息 onGroupMsg
C2C_MESSAGE_CREATE C2C私聊消息 onFriendMsg
GUILD_MESSAGE_CREATE 频道消息 onChannelMsg
DIRECT_MESSAGE_CREATE 频道私信 onDirectMsg

所有这些事件都通过同一个回调地址 /qqbot/webhook 接收,适配器内部会根据事件类型自动分发到对应的处理函数。

使用说明

连接方式说明

1. Webhook 方式

  • 优点:配置简单,不需要额外的中转服务
  • 缺点:需要有公网IP或域名
  • 适用场景:有固定服务器或云服务器的用户

配置完成后,需要在 QQ 开放平台配置 Webhook 回调地址。

2. WebSocket 方式

  • 优点:适合内网环境,通过中转服务连接
  • 缺点:需要额外部署中转服务
  • 适用场景:没有公网IP的本地开发环境

发送模式说明

模式 0:直接发送(推荐)

最简单的模式,直接发送纯文本和图片消息。

模式 1:原生 Markdown

使用 QQ 官方的原生 Markdown 格式发送消息。

模式 3:旧图文模板 Markdown

使用旧版图文混排模板,适合需要复杂排版的场景。

模式 4:纯文模板 Markdown

使用纯文本模板,支持多个文本字段。

模式 5:自定义处理

完全自定义消息处理逻辑。

开发指南

环境要求

  • Node.js >= 16
  • TypeScript >= 5.0
  • Karin 框架

本地开发

  1. 克隆仓库
git clone https://github.com/KarinJS/karin-plugin-adapter-qqbot.git
cd karin-plugin-adapter-qqbot
  1. 安装依赖
npm install
  1. 开发模式运行
npm run dev

构建项目

项目使用 tsup 进行打包,同时会运行 tsc 进行类型检查。

npm run build

构建产物会输出到 dist 目录。

代码检查

npm run lint

发布

# 发布正式版
npm run pub

# 发布测试版
npm run pub-beta

项目结构

karin-plugin-adapter-qqbot/
├── src/
│   ├── connection/      # 连接层(WebSocket、Webhook、路由)
│   ├── core/           # 核心功能(适配器、事件处理、API)
│   ├── types/          # TypeScript 类型定义
│   └── utils/          # 工具函数
├── dist/               # 构建产物
├── config/             # 配置文件目录
├── package.json
├── tsconfig.json       # TypeScript 配置
└── tsup.config.ts      # 打包配置

API 使用示例

发送群消息

import type { AdapterQQBot } from '@karinjs/adapter-qqbot'

// 在你的插件中使用
export class MyPlugin extends plugin {
  async handleGroupMessage(e: KarinMessage) {
    const bot = e.bot as AdapterQQBot
    // 发送消息
    await bot.SendMessage(e.contact, [
      { type: 'text', text: 'Hello, World!' }
    ])
  }
}

撤回消息

await bot.recallMsg(e.contact, messageId)

常见问题

第十步:验证配置

1. 检查配置文件

确保配置文件格式正确:

# 查看配置文件
cat @karinjs/@karinjs-adapter-qqbot/config/config.json

2. 启动服务

# 启动 Karin 服务
npm start
# 或者
node app.js

3. 查看日志

检查日志文件,确认机器人连接成功:

# 查看最新日志
tail -f logs/error/*.log

正常情况下应该看到类似信息:

  • QQBot [AppID] 连接成功
  • Webhook服务已启动,端口: 3000

4. 测试机器人

  1. 将机器人邀请到测试群
  2. 发送消息测试机器人响应
  3. 检查日志确认消息接收正常

第十一步:常见问题排查

问题1:Webhook接收不到消息

检查清单:

  • QQ开放平台回调地址配置正确
  • 服务器防火墙开放对应端口
  • Nginx反向代理配置正确
  • 域名解析正确指向服务器IP

排查命令:

# 检查端口是否监听
netstat -tlnp | grep :3000

# 检查防火墙状态
sudo ufw status

# 测试本地接口
curl -X POST http://localhost:3000/qqbot/webhook

问题2:签名验证失败

可能原因:

  • Secret配置错误
  • 反向代理修改了请求体
  • 时间戳差异过大

解决方案:

# Nginx配置中添加
proxy_buffering off;
proxy_request_buffering off;

问题3:消息发送失败

检查清单:

  • AppID和Secret正确
  • 机器人有发送消息权限
  • API地址配置正确
  • 网络连接正常

问题4:频道消息收不到

可能原因:

  • 频道机器人权限不足
  • guildEnable配置为false
  • 私域机器人未正确配置

解决方案:

{
  "guildEnable": true,
  "guildMode": 1  // 私域机器人使用1
}

第十二步:进阶配置

多机器人配置

[
  {
    "appId": "机器人1的AppID",
    "secret": "机器人1的Secret",
    "event": { "type": 1 }
  },
  {
    "appId": "机器人2的AppID", 
    "secret": "机器人2的Secret",
    "event": { "type": 1 }
  }
]

环境分离配置

开发环境使用沙盒:

{
  "sandbox": true,
  "sandboxApi": "https://sandbox.api.sgroup.qq.com"
}

生产环境使用正式API:

{
  "sandbox": false,
  "prodApi": "https://api.sgroup.qq.com"
}

消息过滤配置

{
  "exclude": [
    "https://example.com",
    "https://trusted-site.com"
  ],
  "regex": [
    {
      "reg": "^/",
      "rep": "#"
    },
    {
      "reg": "\\[图片\\]",
      "rep": ""
    }
  ]
}

更新日志

查看 CHANGELOG.md 了解版本更新历史。

贡献

欢迎提交 Issue 和 Pull Request!

许可证

本项目基于 [项目许可证] 开源。

相关链接

技术支持

如有问题,请通过以下方式获取帮助:

About

karin QQBotAdapter

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 5