From efd166b6ec2f756872fe35b57cdc259dd763c4ef Mon Sep 17 00:00:00 2001 From: rianli Date: Tue, 15 Oct 2024 09:48:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A1=A5=E5=85=85=E7=81=B0=E5=BA=A6?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../public/images/api-231017/feedback_bot.png | Bin 0 -> 3892 bytes .../interface-framework/event-emit.md | 86 ++++++++++-------- 2 files changed, 46 insertions(+), 40 deletions(-) create mode 100644 docs/.vuepress/public/images/api-231017/feedback_bot.png diff --git a/docs/.vuepress/public/images/api-231017/feedback_bot.png b/docs/.vuepress/public/images/api-231017/feedback_bot.png new file mode 100644 index 0000000000000000000000000000000000000000..6e2099d64c4e9987ab9cfd3cc8163aebdb6bc1de GIT binary patch literal 3892 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 当用户在QQ平台内的一些行为操作或某些接口的有异步返回通知确认机制的场景的时候,QQ 会通过"事件"的方式,通知到开发者服务器,开发者可自行根据具体事件通知来进行下一步响应。譬如用户跟机器人发消息,用户添加机器人好友,机器人被拉入群聊等等事件。 --> @@ -9,9 +8,9 @@ ## Webhook方式 -**Webhook方式灰度中,仅灰度用户可使用** 其它用户请使用 [websocket方式](#websocket方式) 。 +webhook事件回调链路目前在灰度验证,灰度用户可体验通过页面配置事件监听及回调地址。如未在灰度范围,可联系QQ机器人反馈助手开通。 -灰度用户如遇问题可通过 [QQ机器人反馈助手](https://mpqq.gtimg.cn/bot-wiki/online/images/api-231017/qqrobot-feedback.jpg) 反馈 +QQ机器人反馈助手 QQ机器人开放平台支持通过使用HTTP接口接收事件。开发者可通过[管理端](https://q.qq.com/qqbot/#/developer/webhook-setting)设定回调地址,监听事件等。 @@ -33,36 +32,39 @@ QQ机器人开放平台支持通过使用HTTP接口接收事件。开发者可 `opcode` 含义如下: -| **CODE** | **名称** | **客户端行为** | **描述** | -| --- | --- | --- | --- | -| 0 | Dispatch | Receive | 服务端进行消息推送 | -| 13 | 回调地址验证 | Receive | 开放平台对机器人服务端进行验证 | +| **CODE** | **名称** | **客户端行为** | **描述** | +|----------|----------|-----------|-----------------| +| 0 | Dispatch | Receive | 服务端进行消息推送 | +| 13 | 回调地址验证 | Receive | 开放平台对机器人服务端进行验证 | ### 签名校验 + 机器人服务端需要对回调请求进行签名验证以保证数据没有被篡改过。 [签名算法](sign.md) ### 回调地址及事件监听配置 开发者需要提供一个HTTPS回调地址。并选定监听的事件类型。开放平台会将事件通过回调的方式推送给机器人。 + event_subscription 配置回调地址后,开放平台会对回调地址进行验证: * 请求结构(Payload.d) -| **字段** | **描述** | -| --- |------------| +| **字段** | **描述** | +|-------------|------------| | plain_token | 需要计算签名的字符串 | -| event_ts | 计算签名使用时间戳 | +| event_ts | 计算签名使用时间戳 | * 返回结果 -| **字段** | **描述** | -| --- |-------------| +| **字段** | **描述** | +|-------------|------------| | plain_token | 需要计算签名的字符串 | -| signature | 签名 | +| signature | 签名 | 计算过程如下(golang): + ```go func handleValidation(rw http.ResponseWriter, r *http.Request, botSecret string) { httpBody, err := io.ReadAll(r.Body) @@ -131,6 +133,8 @@ body: {"plain_token": "Arq0D5A61EgUu4OxUvOp","signature": "87befc99c42c651b3aac0 ## WebSocket方式 +* websocket 事件推送链路将在24年年底前逐步下线,后续官方不再维护。 + 通过 `WebSocket` 建立与QQ机器人开放平台的长链接通信管道,当需要事件通知的时候QQ后台通过 `WebSocket` 连接下发事件到开发者服务器上。 开发者需要维护 `WebSocket` 长链接的状态,包括连接状态维护、登录鉴权、心跳维护、断线恢复重连等。 @@ -139,7 +143,7 @@ body: {"plain_token": "Arq0D5A61EgUu4OxUvOp","signature": "87befc99c42c651b3aac0 ### 通用数据结构 Payload - `payload` 指的是在 `websocket` 连接上传输的数据,网关的上下行消息采用的都是同一个结构,如下: +`payload` 指的是在 `websocket` 连接上传输的数据,网关的上下行消息采用的都是同一个结构,如下: ```json { @@ -149,29 +153,30 @@ body: {"plain_token": "Arq0D5A61EgUu4OxUvOp","signature": "87befc99c42c651b3aac0 "t": "GATEWAY_EVENT_NAME" } ``` -| 字段 | 描述| -| ----- | ----- | -| op |指的是 opcode,参考连接维护 | -| s |下行消息都会有一个序列号,标识消息的唯一性,客户端需要再发送心跳的时候,携带客户端收到的最新的s | -| t |代表事件类型。主要用在op为 0 Dispatch 的时候| -| d |代表事件内容,不同事件类型的事件内容格式都不同,请注意识别。主要用在op为 0 Dispatch 的时候| + +| 字段 | 描述 | +|-----|------------------------------------------------------| +| op | 指的是 opcode,参考连接维护 | +| s | 下行消息都会有一个序列号,标识消息的唯一性,客户端需要再发送心跳的时候,携带客户端收到的最新的s | +| t | 代表事件类型。主要用在op为 0 Dispatch 的时候 | +| d | 代表事件内容,不同事件类型的事件内容格式都不同,请注意识别。主要用在op为 0 Dispatch 的时候 | ### 长连接维护 OpCode 所有 `opcode` 列表如下: -| **CODE** | **名称** | **客户端行为** | **描述** | -| --- | --- | --- | --- | -| 0 | Dispatch | Receive | 服务端进行消息推送 | -| 1 | Heartbeat | Send/Receive | 客户端或服务端发送心跳 | -| 2 | Identify | Send | 客户端发送鉴权 | -| 6 | Resume | Send | 客户端恢复连接 | -| 7 | Reconnect | Receive | 服务端通知客户端重新连接 | -| 9 | Invalid Session | Receive | 当 identify 或 resume 的时候,如果参数有错,服务端会返回该消息 | -| 10 | Hello | Receive | 当客户端与网关建立 ws 连接之后,网关下发的第一条消息 | -| 11 | Heartbeat ACK | Receive/Reply | 当发送心跳成功之后,就会收到该消息 | -| 12 | HTTP Callback ACK | Reply | 仅用于 http 回调模式的回包,代表机器人收到了平台推送的数据 | +| **CODE** | **名称** | **客户端行为** | **描述** | +|----------|-------------------|---------------|------------------------------------------| +| 0 | Dispatch | Receive | 服务端进行消息推送 | +| 1 | Heartbeat | Send/Receive | 客户端或服务端发送心跳 | +| 2 | Identify | Send | 客户端发送鉴权 | +| 6 | Resume | Send | 客户端恢复连接 | +| 7 | Reconnect | Receive | 服务端通知客户端重新连接 | +| 9 | Invalid Session | Receive | 当 identify 或 resume 的时候,如果参数有错,服务端会返回该消息 | +| 10 | Hello | Receive | 当客户端与网关建立 ws 连接之后,网关下发的第一条消息 | +| 11 | Heartbeat ACK | Receive/Reply | 当发送心跳成功之后,就会收到该消息 | +| 12 | HTTP Callback ACK | Reply | 仅用于 http 回调模式的回包,代表机器人收到了平台推送的数据 | 客户端行为含义如下: @@ -223,12 +228,12 @@ wss://api.sgroup.qq.com/websocket/ ``` -| **字段** | **描述** | -| --- | --- | -| token | 格式为"QQBot {AccessToken}" | -| intents | 是此次连接所需要接收的事件,具体可参考 **Intents** [事件订阅intents\|QQ机器人文档](#事件订阅Intents)| -| shard | 考虑到开发者事件接收时可以实现负载均衡,QQ 提供了分片逻辑,事件通知会落在不同的分片上,该参数是个拥有两个元素的数组。
例如:\[0,4\],代表分为四个片,当前链接是第 0 个片,业务稍后应该继续建立 `shard` 为\[1,4\],\[2,4\],\[3,4\]的链接,才能完整接收事件,更多详细的内容可以参考 **Shard** [Shard机制\|QQ机器人文档](#%E5%88%86%E7%89%87%E8%BF%9E%E6%8E%A5LoadBalance)
若无需分片,使用\[0, 1\]即可。 | -| properties | 目前无实际作用,可以按照自己的实际情况填写,也可以留空 | +| **字段** | **描述** | +|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| token | 格式为"QQBot {AccessToken}" | +| intents | 是此次连接所需要接收的事件,具体可参考 **Intents** [事件订阅intents\ |QQ机器人文档](#事件订阅Intents)| +| shard | 考虑到开发者事件接收时可以实现负载均衡,QQ 提供了分片逻辑,事件通知会落在不同的分片上,该参数是个拥有两个元素的数组。
例如:\[0,4\],代表分为四个片,当前链接是第 0 个片,业务稍后应该继续建立 `shard` 为\[1,4\],\[2,4\],\[3,4\]的链接,才能完整接收事件,更多详细的内容可以参考 **Shard** [Shard机制\ |QQ机器人文档](#%E5%88%86%E7%89%87%E8%BF%9E%E6%8E%A5LoadBalance)
若无需分片,使用\[0, 1\]即可。 | +| properties | 目前无实际作用,可以按照自己的实际情况填写,也可以留空 | 鉴权成功之后,QQ 后台会下发一个 Ready Event, `payload` 如下: ```json @@ -259,7 +264,6 @@ wss://api.sgroup.qq.com/websocket/ } ``` - 心跳发送成功之后会收到 [OpCode 11 Heartbeat ACK](opcode.md) 消息, `payload` 如下: ```json @@ -382,16 +386,16 @@ PUBLIC_GUILD_MESSAGES (1 << 30) // 消息事件,此为公域的消息事件 如果拥有的某个特殊事件类型的权限被取消,则在当前连接上不会报错,但是将不会收到对应的事件类型,如果重新连接,则报错,所以如果开发者的事件类型权限被取消,请及时调整监听事件代码,避免报错导致的无法连接。 - ### 分片连接LoadBalance 随着`bot`的增长并被添加到越来越多的频道中,事件越来越多,业务有必要对事件进行水平分割,实现负载均衡。机器人网关实现了一种用户可控制的分片方法,该方法允许跨多个网关连接拆分事件。 分片完全由用户控制,并且不需要在单独的连接之间进行状态共享。 要在连接上启用分片,需要在建立连接的时候指定分片参数,具体参考[gateway](reference.md) - #### 获得合适的分片数 + 使用[/gateway/bot](../../openapi/wss/shard_url_get.md)接口获取网关地址的时候,会同时返回一个建议的 `shard`数,及最大并发限制。 + ```json { "url": "wss://sandbox.api.sgroup.qq.com/websocket", @@ -406,7 +410,9 @@ PUBLIC_GUILD_MESSAGES (1 << 30) // 消息事件,此为公域的消息事件 ``` #### 分片规则 + 分片是按照频道id进行哈希的,同一个频道的信息会固定从同一个链接推送。具体哈希计算规则如下: + ```bash shard_id = (guild_id >> 22) % num_shards ```