# 客服交互流程描述

小程序客服能力,复用QQ聊天机器人能力,以下以QQ聊天机器人指代客服号。 当前,客服能力仅支持在用户主动发消息后,客服号才能进行回复,不支持主动向用户推送消息。 开发者需要在管理端申请开通,目前功能正在内测中,满足内测资格即可在开发者管理端看到开通入口。

打开客服入口:

<button open-type="contact" bindcontact="onEnterContact"> 进入机器人客服 </button>
1

# QQ聊天机器人消息交互

交互逻辑1

每轮交互由 QQ 发起(步骤2),机器人接收到消息之后,应先立即给 QQ 回确认包(包体内容可以为空;步骤3);然后再异步回调 QQ 接口,将机器人回复的消息推送给QQ(步骤4)。 步骤2中,QQ 会带上消息唯一标识MsgId给机器人;机器人在异步回调时,需要将MsgId原样带回给QQ。

MsgId 有有效期,目前为3分钟,所以请在3分钟内回复消息,超过3分钟会话会过期,就无法回复消息了。

# 机器人发消息给QQ

# 请求方式

POST

# 接口参数

https://app.qun.qq.com/robotapi/msg_reply/v2?ts=xxx&appid=123&nonce=123&sig=abcd

# 请求包体

Content-Type: application/json, text/json

[
    {
    "receiverId": "abcdef",
    "groupId": "abcdef",
    "content": [
        {"type":0,"data":"文本消息内容"},
        {"type":1,"data":"被@用户ID","info":"被@用户昵称"},
        {"type":2,"data":"图片文件ID","info":"pic","mediaInfo":"图片文件信息"},
        {"type":3,"data":"语音文件ID","info":"语音文件格式","size":"语音文件大小","md5":"语音文件md5值"},
        {"type":4,"data":"微笑","info":"face"}
    ],
    "msgType": 0,
    "masterId": "SampleString4",
    "msgId": "SampleString5",
    "timestamp": 1559032351,
    "status": 7,
    "errorMsg": "SampleString8"
  	},
    {
    "receiverId": "abcdef123123",
    "groupId": "abcdef22",
    "content": [
        {"type":0,"data":"文本消息内容"},
        {"type":1,"data":"被@用户ID","info":"被@用户昵称"},
        {"type":2,"data":"图片文件ID","info":"pic","mediaInfo":"图片文件信息"},
        {"type":3,"data":"语音文件ID","info":"语音文件格式","size":"语音文件大小","md5":"语音文件md5值"},
        {"type":4,"data":"微笑","info":"face"}
    ],
    "msgType": 0,
    "masterId": "SampleString4",
    "msgId": "demoMsgId",
    "timestamp": 1559032351,
    "status": 7,
    "errorMsg": "SampleString8"
  	}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

该接口支持同时向多个群回复消息,用于减少接口交互,提升发消息效率。

此接口为批量接口,body 为 json数组,数组的每一项为一条消息

消息内容各个字段含义:

字段名 是否必填 字段含义
receiverId 消息要发送到的用户Id,值取自QQ聊天机器人富媒体消息中的senderId
groupId 群消息必填 消息要发送到的群Id,值取自QQ聊天机器人富媒体消息中的groupId
content 消息内容,参考聊天协议描述
msgType 0 为群消息,1 为c2c消息
masterId 机器人平台内部使用字段,值取自QQ聊天机器人富媒体消息中的masterId
msgId 消息的id,值取自QQ聊天机器人富媒体消息中的msgId
timestamp 消息的触发时间,值取自QQ聊天机器人富媒体消息中的timestamp
status
errorMsg

# 返回包体

200 Created; 400 Bad Request;

# 有关富媒体消息

消息类型中,type=2 和 type=3 为富媒体消息,需要先调用下述QQ聊天机器人富媒体消息接口上传文件,才能够发消息。 富媒体文件上传到QQ平台后,有有效期,如果资源过期,会有包体提示:

Content-Type: application/json, text/json

[
  {
	  "errorCode": "-5103059",
		"msgId": "abcd"
	},
	{
		"errorCode": "-5103059",
		"msgId": "efgh"
	}
]
1
2
3
4
5
6
7
8
9
10

# QQ聊天机器人富媒体消息

交互逻辑2

当前支持图片语音富文本消息,以及图文混排消息 等富媒体消息。和普通文本消息相比,机器人发送富文本消息之前需要先将文件上传到 QQ 后台(步骤4),获取到文件存储在 QQ 后台的相关信息(如mediaid 和 mediainfo,步骤5),然后再把文件相关信息和文本消息一起推送给 QQ 接口(步骤6)。 文件 md5 和 mediaid、mediainfo 三元组构成文件在 QQ 后台内部的唯一标识,有效期是7天,其中图片三元组数据可重复使用的最大次数为200(语音无次数限制)。第三方可以缓存该三元组数据,提高机器人响应用户的速度和节约流量。

QQ接收到富文本消息之后会校验文件 md5 和 mediaid、mediainfo 三元组信息。如果校验失败(失效或者不可重复使用)QQ将在回包里以错误码形式告知机器人(步骤7),机器人可以对这种情况进行柔性处理,比如改为下发文本消息(步骤8)。

# 请求通用签名算法

接入方统一使用该方法进行签名验证,假设目前有如下参数

参数 类型 说明
appid uint32 2222222 申请到的appid
ts uint32 1465185768 请求时间
nonce uint32 562341234 随机正整数
json {"xxxx": 123} post body,没有参数名,这里直接对于 post body 后续直接称为 body

# 对参数排序

首先对所有请求参数按参数名的字典序( ASCII 码)升序排序
注意:
1)只按参数名进行排序,参数值保持对应即可,不参与比大小;
2)按 ASCII 码比大小,如 InstanceIds.2 要排在 InstanceIds.12 后面,不是按字母表,也不是按数值。
用户可以借助编程语言中的相关排序函数来实现这一功能,如 php 中的 ksort 函数。

上述示例参数的排序结果如下:

'appid' : 2222222
'nonce' : 562341234,
'ts' : 1465185768
1
2
3

# 拼接请求字符串

此步骤生成请求字符串。 将把上一步排序好的请求参数格式化成“参数名称”=“参数值”的形式
注意:“参数名称“和“参数值”为原始值而非url编码后的值。
然后将格式化后的各个参数用"&"拼接在一起。

最终生成的请求字符串为:

appid=2222222&nonce=562341234&ts=1465185768

# 拼接签名原文

此步骤生成签名原文字符串。 签名原文字符串由以下几个参数构成:
请求方法: 支持 POST 和 GET 方式,样例使用 POST 请求,注意方法为全大写。
请求主机: 根据实际请求的域名填写
接口域名:app.qun.qq.com
请求路径:/robotapi/msg_reply/v2
请求字符串: 即上一步生成的请求字符串
请求body: post 请求的时候,发出的包体原文(如果是上传文件等操作,则不需要拼接body)

签名原文串的拼接规则为:

请求方法 + 请求域名 + 请求路径 + ? + 请求字符串 + 请求body

示例的拼接结果为:

POSTapp.qun.qq.com/robotapi/msg_reply/v2?appid=2222222&nonce=562341234&ts=1465185768&{"xxxx": 123}

# 生成签名串

此步骤生成签名串。 首先使用 HMAC-SHA1 算法对上一步中获得的签名原文字符串进行签名,然后将生成的签名串使用 Base64 进行编码,即可获得最终的签名串。

具体代码如下,以 PHP 语言为例:

$appkey = 'fakeAppkey'; 
$srcStr = 'POSTapp.qun.qq.com/robotapi/msg_reply/v2?appid=2222222&nonce=562341234&ts=1465185768&{"xxxx": 123}';
$signStr = base64_encode(hash_hmac('sha1', $srcStr, $appkey, true));
echo $signStr;
1
2
3
4

最终得到的签名串为:

whXBY/0lXFDtYGj0FvTTjem0tlw=

使用其它程序设计语言开发时,可用上面示例中的原文进行签名验证,得到的签名串与例子中的一致即可。

# 签名串编码

生成的签名串并不能直接作为请求参数,需要对其进行 URL 编码。
非 ASCII 字符在 URL 编码前需要先以 UTF-8 进行编码。

如上一步生成的签名串为:

whXBY/0lXFDtYGj0FvTTjem0tlw=

经过 urlencode 之后,最终得到的签名串请求参数(SIGNTURE)为:

whXBY%2F0lXFDtYGj0FvTTjem0tlw%3D

注意:有些编程语言的 http 库会自动为所有参数进行 urlencode ,在这种情况下,就不需要对签名串进行 URL 编码了,否则两次 URL 编码会导致签名失败。

# 聊天协议描述

# 协议描述

# 请求GET参数

参数 类型 说明
ts uint32 请求时间
sig string 请求包签名,不同场景生成方式不同
appid uint32 申请到的appid

# POST 数据

参数 类型 说明
msgType uint32 1为C2C消息
senderId string QQ用户ID
senderNickname string QQ用户昵称
location 复合类型 经纬度
type uint32 消息内容类型,取值参考下面表格
data string 消息内容
info string 消息内容扩展
md5 string 文件md5值
size uint32 文件大小
duration uint32 语音时长
msgId string QQ生成,机器人不需要理解;机器人推消息给QQ时带上
masterId string QQ生成,机器人不需要理解;机器人推消息给QQ时带上
mediaId string 文件标识
mediaInfo string 文件信息
thirdTopicId int 第三方在设置页面设置保存的会话主题ID,用于识别群的会话主题,进行处理,有总量限制,需要特殊申请

根据 type 不同,data 与 info 的含义不同,具体如下:

type data info 备注
0 "文本消息内容"
1 "被@的QQ用户ID" "被@用户昵称"
2 "图片文件mediaid" "pic"
3 "语音文件mediaid" "silk"
4 "QQ系统表情文字" "face"
15 视频消息 上传后返回的videoId

# 消息和文件规格

已支持长消息

# 语音文件规格

  • 时长必须大于1秒
  • 每帧时长为10毫秒
  • 每个data只包含1帧数据
  • 总时长不超过5分钟
  • 总大小不超过 28MB
  • 有效期7天
  • 支持 silk 格式

# 图片文件规格

  • 宽和长都不能超过 0x7fff(32767) 像素点值;
  • 总大小不超过 10MB;
  • 暂不支持 H265 编码;
  • 支持 jpeg/png/gif;
  • 资源有效期 7 天
  • 可重复使用最大次数 200 次

# 视频文件规格

  • 总大小不超过 28MB
  • 视频支持 mp4 格式,缩略图支持 png/jpg 格式
  • 资源有效期 7 天
  • 可重复使用最大次数 200 次

# 机器人上传富媒体

# 请求方式

POST

# 接口参数

# 语音文件

# 通过msgid上传(互动消息使用)

https://app.qun.qq.com/robotapi/media_upload/v2?ts=xx&info=silk&size=1234&md5=abc&msgid=aaa&duration=123&appid=1&sig=abcd

# 通过c2c上传(c2c推送使用)

https://app.qun.qq.com/robotapi/media_upload/v2?ts=xx&info=silk&size=1234&md5=abc&c2c=1&duration=123&appid=1&sig=abcd

语音文件上传QQ请求参数sig只计算url参数,不计算文件本身

语音仅支持silk格式

# 图片文件

# 通过msgid上传(互动消息使用)

https://app.qun.qq.com/robotapi/media_upload/v2?ts=xx&info=pic&size=1234&md5=abc&msgid=aaa&appid=1&sig=abcd

# 通过c2c上传(c2c推送使用)

https://app.qun.qq.com/robotapi/media_upload/v2?ts=xx&info=pic&size=1234&md5=abc&c2c=1&appid=1&sig=abcd

图片文件上传QQ请求参数sig只计算url参数,不计算文件本身

图片支持jpg,png,gif格式

# 请求包体

请求包 Content-Type: multipart/form-data,图片和语音文件的form-data字段名为file

[
    "Multipart格式保存二进制数据"
]
1
2
3

# 返回包体

Content-Type: application/json, text/json

{
    "mediaId": "abcd",
    "md5": "abcd",
    "size": "123",
    "msgid": "abcd",
    "mediaInfo": "abcd"
}
1
2
3
4
5
6
7

获取到的相关信息,可以用于在发送消息的接口中,发送富媒体消息。

# 机器人下载图片、音频等

# 请求方式

GET

# 接口参数

https://app.qun.qq.com/robotapi/media_download/v2?msgid=abc&mediaid=abcd&md5=abc&size=123&info=abc&ts=xxx&appid=123&nonce=123&sig=abcd

# 返回包体

[
    "图片/音频等二进制数据"
]
1
2
3

注: 语音下载,对于60秒以内的语音,如果语音转文本成功,会在http 回包的header中增加key value的param: metadata:{"srResult":"url base64编码的utf8语音识别结果"}, srResult值: utf8编码的中英文识别结果,再通过url base64编码得到的字符串(http 标准中的header并没有明确支持汉字,所以通过url base64编码)