napcat
对接 NapCatQQ(OneBot 11 协议)的 Go 软件包,零第三方依赖(仅 gorilla/websocket)。
bot := napcat.New().SetToken("xxx").SetForwardWS("ws://127.0.0.1:3001")
bot.OnGroupMessage(func(c *napcat.Context) {
if c.HasAtMe() {
c.ReplyText("hi")
}
})
bot.Run(ctx)
特性
- 一个对象搞定:
New()创建与 NapCat 交互的客户端对象,配置、事件、API 全在对象上 - 四种通信方式,链式配置、可任意叠加:
- 正向 WebSocket(自动重连 + 指数退避)
- 反向 WebSocket(支持多 bot 实例同时连入)
- HTTP API
- HTTP POST 上报(自动支持 OneBot 快速操作)
- 事件模型:message / message_sent / notice / request / meta_event 全量结构化,
notice 未知字段不丢失(收进
Extra) - 消息段:全类型构造函数;收到的 CQ 码字符串与段数组统一解码
- API 覆盖:OneBot 11 标准 + go-cqhttp 兼容 + NapCat 扩展共 80+ 个类型化方法,
未收录的扩展可用
Call裸调 - echo 路由:WS 上的 action 请求/响应按 echo 精确配对,支持并发调用
- 连接级路由:事件处理函数里的 API 调用自动走产生该事件的连接,多 bot 互不串线
- 内置文本命令路由、请求 Approve/Reject、心跳记录、panic 隔离
目录结构
napcat/
├── doc.go 包文档(pkg.go.dev 首页)
├── client.go Client:配置方法、连接汇聚、事件分发、Handler 注册
├── context.go Context:处理函数上下文(Reply/Approve/快速操作)
├── api.go API:80+ 类型化 API 方法
├── caller.go Caller 接口 + WS echo 路由 + CallAPI 泛型
├── connect_ws.go 正向/反向 WebSocket 连接器 + Session
├── connect_http.go HTTP 上报(快速操作)+ HTTP API 连接器
├── event.go 事件结构(message/notice/request/meta)
├── segment.go 消息段构造与解码
├── cqcode.go CQ 码解析/编码
├── types.go 响应信封与实体类型
├── example_test.go 用法示例(godoc Examples)
└── *_test.go 单元测试(内置 mock NapCat)
安装
go get gitea.doicat.com/duoduo/napcat
使用指定版本:
go get gitea.doicat.com/duoduo/napcat@v1.0.0
私有仓库使用者:如果仓库设为私有,除了给 Git 配置 Gitea 凭据外,还需设置:
set GOPRIVATE=gitea.doicat.com
这样 go 命令才会走 Git 凭据拉取而不是公共校验和数据库。
快速开始
1. NapCat 侧配置
在 NapCat WebUI 的「网络配置」里按需启用一项(或多项):
| 配置方法 | NapCat 侧配置 |
|---|---|
SetForwardWS("ws://127.0.0.1:3001") |
启用「WebSocket 服务器」,端口 3001 |
SetReverseWS(":8080") |
启用「WebSocket 客户端」,URL 填 ws://<本机IP>:8080/ |
SetHTTPAPI("http://127.0.0.1:3000") |
启用「HTTP 服务器」,端口 3000 |
SetHTTPReport(":8081") |
启用「HTTP POST 上报」,地址填 http://<本机IP>:8081/ |
若配置了 access_token,SetToken 填同一个值即可,框架会在 WS 握手
(query + Authorization 头)和 HTTP 调用(Authorization 头)中自动携带;
HTTP 上报场景若配了 secret,SetSecret 会自动校验 X-Signature(HMAC-SHA1)。
2. 完整示例
package main
import (
"context"
"os"
"os/signal"
"napcat"
)
func main() {
bot := napcat.New().
SetToken("your-token").
SetForwardWS("ws://127.0.0.1:3001")
// 可叠加其他通信方式:
// bot.SetReverseWS(":8080")
// bot.SetHTTPAPI("http://127.0.0.1:3000")
// bot.SetHTTPReport(":8081")
// 文本命令
bot.OnCommand("/ping", func(c *napcat.Context, args []string) {
c.ReplyText("pong!")
})
// 群里 @机器人 就复读
bot.OnGroupMessage(func(c *napcat.Context) {
if c.HasAtMe() && !c.IsSelfMessage() {
c.ReplyText("收到: " + c.PlainText())
}
})
// 进群欢迎
bot.OnNoticeType("group_increase", func(c *napcat.Context) {
c.SendGroupMsg(nil, c.Event.Notice.GroupID, napcat.Text("欢迎新人~"))
})
// 被戳就戳回去
bot.OnNoticeType("notify", func(c *napcat.Context) {
n := c.Event.Notice
if n.SubType == "poke" && n.TargetID == c.SelfID() {
c.SendPoke(nil, n.GroupID, n.UserID)
}
})
// 好友/群请求自动同意
bot.OnRequest(func(c *napcat.Context) {
c.Approve()
})
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
bot.Run(ctx)
}
配置方法一览
| 方法 | 说明 |
|---|---|
SetToken(t) |
OneBot access_token,所有连接自动携带 |
SetSecret(s) |
HTTP 上报 X-Signature 校验密钥 |
SetLogger(l) |
自定义 *slog.Logger |
SetForwardWS(urls...) |
正向 WS 目标,可多个,重复调用替换 |
SetReverseWS(addrs...) |
反向 WS 监听地址,可多个,重复调用替换 |
SetHTTPAPI(baseURL) |
HTTP API 地址 |
SetHTTPReport(addrs...) |
HTTP 上报监听地址,可多个,重复调用替换 |
Use(conn...) |
注册自定义 Connector(高级扩展点) |
以上方法均返回 *Client,支持链式调用。请勿在 Run 之后修改配置。
事件处理
bot.OnEvent(fn) // 所有事件
bot.OnMessage(fn) // 私聊 + 群聊消息(含 message_sent)
bot.OnPrivateMessage(fn) // 私聊消息
bot.OnGroupMessage(fn) // 群聊消息
bot.OnNotice(fn) // 全部通知
bot.OnNoticeType(t, fn) // 指定 notice_type,如 "group_increase" "notify" "group_recall"
bot.OnRequest(fn) // 好友/群请求
bot.OnMeta(fn) // 心跳/生命周期
bot.OnCommand(name, fn) // 文本命令,args 为空白切分的参数
同一会话的事件串行分发(保序);handler 里的 panic 会被隔离并记录日志。 事件队列上限 256 条,溢出时丢弃并告警。
Context 常用方法
| 方法 | 说明 |
|---|---|
Reply(msg...) / ReplyText(s) |
回复当前消息(群聊/私聊自动判断) |
Recall() |
撤回当前消息 |
Approve() / Reject(reason) |
同意/拒绝当前的请求事件 |
HasAtMe() / PlainText() / Segments() |
消息内容判断 |
IsGroup() / IsPrivate() / IsSelfMessage() |
事件类型判断 |
SendGroupMsg(nil, gid, ...) 等 |
直接调用任意 API(ctx 传 nil 用默认 30s 超时) |
Call(nil, action, params, &out) |
裸调未收录的扩展 API |
HTTP 上报模式下,Reply / Approve / Reject 会随 HTTP 响应以
OneBot「快速操作」返回,不产生额外请求。
消息段
napcat.Text("hello")
napcat.At(12345) // napcat.AtAll()
napcat.Image("C:/a.jpg") // 支持本地路径 / http(s) URL / base64://
napcat.Reply(678).With("text", "引用") // With 追加任意字段
napcat.CustomNode(10001, "某人", []napcat.Segment{napcat.Text("...")})
收到的消息统一用 c.Segments() 获取,CQ 码字符串会被自动解析;
napcat.ParseCQ / napcat.EncodeCQ 可单独使用。
API 调用
全部 API 挂在 Client(默认通道)与 Context(事件来源通道)上,
命名与 OneBot action 一一对应(驼峰化),例如:
login, _ := bot.GetLoginInfo(nil) // get_login_info
mid, err := bot.SendGroupMsg(nil, 123, napcat.Text("hi"))
bot.SetGroupBan(nil, 123, 456, 600) // set_group_ban
info, _ := bot.GetGroupMemberInfo(nil, 123, 456, false)
bot.UploadGroupFile(nil, 123, `C:\file.zip`, "file.zip", "")
hist, _ := bot.GetGroupMsgHistory(nil, 123, 0, 20, false)
返回未结构化的 NapCat 扩展 API(如 GetProfileLike)时得到 jsonRaw(map),
需要更细的结构时用 Call 裸调自行解码。
测试
go test ./...
测试内置 mock NapCat(正向 WS、反向 WS、HTTP 上报签名校验、HTTP API), 覆盖 echo 往返、错误响应、快速操作、命令分发、CQ 码转义回环等场景。
注意事项
message_sent是 bot 自己发出的消息事件,同样进入 message 处理链, 用c.IsSelfMessage()区分,避免 bot 复读自己。- 多个 bot 实例同时连入反向 WS 时,
Client.Call(默认通道)只作用于 最近连入的会话;事件处理内请一律用Context的方法,自动路由正确。 - 正向 WS 断开后自动重连(1s 起步、30s 封顶指数退避)。