1、客服消息功能概述
在頁(yè)面中使用 <contact-button/> 可以顯示進(jìn)入客服會(huì)話按鈕。
當(dāng)用戶在客服會(huì)話發(fā)送消息(或進(jìn)行某些特定的用戶操作引發(fā)的事件推送時(shí)),微信服務(wù)器會(huì)將消息(或事件)的數(shù)據(jù)包(JSON或者XML格式)POST請(qǐng)求開(kāi)發(fā)者填寫的URL。開(kāi)發(fā)者收到請(qǐng)求后可以使用發(fā)送客服消息接口進(jìn)行異步回復(fù)。
微信服務(wù)器在將用戶的消息發(fā)給小程序的開(kāi)發(fā)者服務(wù)器地址(開(kāi)發(fā)設(shè)置處配置)后,微信服務(wù)器在五秒內(nèi)收不到響應(yīng)會(huì)斷掉連接,并且重新發(fā)起請(qǐng)求,總共重試三次,如果在調(diào)試中,發(fā)現(xiàn)用戶無(wú)法收到響應(yīng)的消息,可以檢查是否消息處理超時(shí)。關(guān)于重試的消息排重,有msgid的消息推薦使用msgid排重。事件類型消息推薦使用FromUserName + CreateTime 排重。
-
服務(wù)器收到請(qǐng)求必須做出下述回復(fù),這樣微信服務(wù)器才不會(huì)對(duì)此作任何處理,并且不會(huì)發(fā)起重試,否則,將出現(xiàn)嚴(yán)重的錯(cuò)誤提示。詳見(jiàn)下面說(shuō)明:
1、直接回復(fù)success(推薦方式) 2、直接回復(fù)空串(指字節(jié)長(zhǎng)度為0的空字符串,而不是結(jié)構(gòu)體中content字段的內(nèi)容為空)
-
一旦遇到以下情況,微信都會(huì)在小程序會(huì)話中,向用戶下發(fā)系統(tǒng)提示“該小程序客服暫時(shí)無(wú)法提供服務(wù),請(qǐng)稍后再試”:
1、開(kāi)發(fā)者在5秒內(nèi)未回復(fù)任何內(nèi)容 2、開(kāi)發(fā)者回復(fù)了異常數(shù)據(jù)
-
小程序客服消息界面效果展示
小程序客服消息列表展示
2、網(wǎng)頁(yè)版客服工具
具體可參考https://mp.weixin.qq.com/debug/wxadoc/introduction/custom.html#網(wǎng)頁(yè)版客服工具
3、客服消息功能具體實(shí)現(xiàn)
-
消息推送配置
-
填寫服務(wù)器配置
-
驗(yàn)證消息的確來(lái)自微信服務(wù)器
開(kāi)發(fā)者提交信息后,微信服務(wù)器將發(fā)送GET請(qǐng)求到填寫的服務(wù)器地址URL上,GET請(qǐng)求攜帶參數(shù)如下表所示:
/**
* 檢驗(yàn)signature對(duì)請(qǐng)求進(jìn)行校驗(yàn)
*/
function checkSignature(params){
//token 就是自己填寫的令牌
var key=[token, params.timestamp, params.nonce].sort().join('');
//將token (自己設(shè)置的) 、timestamp(時(shí)間戳)、nonce(隨機(jī)數(shù))三個(gè)參數(shù)進(jìn)行字典排序
var sha1 = crypto.createHash('sha1');
//將上面三個(gè)字符串拼接成一個(gè)字符串再進(jìn)行sha1加密
sha1.update(key);
return sha1.digest('hex') === params.signature;
//將加密后的字符串與signature進(jìn)行對(duì)比,若成功,返回echostr
}
-
小程序界面實(shí)現(xiàn)
-
contact-button
客服會(huì)話按鈕,用于在頁(yè)面上顯示一個(gè)客服會(huì)話按鈕,用戶點(diǎn)擊該按鈕后會(huì)進(jìn)入客服會(huì)話。
<!--index.wxml-->
<view class="container">
<view bindtap="bindViewTap" class="userinfo">
<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</view>
<view class="user motto">
<contact-button type="default-light" size="30" session-from="weapp" class="guest-button">
</contact-button>
</view>
</view>
-
contact-button只有2中類型:圖標(biāo)部分無(wú)法改變
-
服務(wù)器接收消息事件
-
進(jìn)入會(huì)話事件
用戶在小程序“客服會(huì)話按鈕”進(jìn)入客服會(huì)話時(shí)將產(chǎn)生如下數(shù)據(jù)包:
{
"ToUserName": "toUser",
"FromUserName": "fromUser",
"CreateTime": 1482048670,
"MsgType": "event",
"Event": "user_enter_tempsession",
"SessionFrom": "sessionFrom"
}
-
文本消息
用戶在客服會(huì)話中發(fā)送文本消息時(shí)將產(chǎn)生如下數(shù)據(jù)包:
{
"ToUserName": "toUser",
"FromUserName": "fromUser",
"CreateTime": 1482048670,
"MsgType": "text",
"Content": "this is a test",
"MsgId": 1234567890123456
}
-
圖片消息
用戶在客服會(huì)話中發(fā)送圖片消息時(shí)將產(chǎn)生如下數(shù)據(jù)包:
{
"ToUserName": "toUser",
"FromUserName": "fromUser",
"CreateTime": 1482048670,
"MsgType": "image",
"PicUrl": "this is a url",
"MediaId": "media_id",
"MsgId": 1234567890123456
}
-
網(wǎng)頁(yè)版客服工具進(jìn)入會(huì)話事件
用戶在小程序“客服會(huì)話按鈕”進(jìn)入客服會(huì)話時(shí)將產(chǎn)生如下數(shù)據(jù)包:
{
"ToUserName": "toUser",
"FromUserName": "fromUser",
"CreateTime": 1482048670,
"MsgType": "event",
"Event": "kf_create_session",
"KfAccount": "kf2001@gh_93228be5b792"
}
-
獲取 access_token
請(qǐng)參考手把手教你開(kāi)發(fā)微信小程序之模版消息中獲取 access_token
-
接收事件并回復(fù)消息
-
功能概述
當(dāng)用戶和小程序客服產(chǎn)生特定動(dòng)作的交互時(shí)(具體動(dòng)作列表請(qǐng)見(jiàn)下方說(shuō)明),微信將會(huì)把消息數(shù)據(jù)推送給開(kāi)發(fā)者,開(kāi)發(fā)者可以在一段時(shí)間內(nèi)(目前修改為48小時(shí))調(diào)用客服接口,通過(guò)POST一個(gè)JSON數(shù)據(jù)包來(lái)發(fā)送消息給普通用戶。此接口主要用于客服等有人工消息處理環(huán)節(jié)的功能,方便開(kāi)發(fā)者為用戶提供更加優(yōu)質(zhì)的服務(wù)。
目前允許的動(dòng)作列表如下,不同動(dòng)作觸發(fā)后,允許的客服接口下發(fā)消息條數(shù)和下發(fā)時(shí)限不同。下發(fā)條數(shù)達(dá)到上限后,會(huì)收到錯(cuò)誤返回碼,具體請(qǐng)見(jiàn)返回碼說(shuō)明頁(yè):
-
客服接口-發(fā)消息
-
接口調(diào)用請(qǐng)求說(shuō)明:
http請(qǐng)求方式: POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
各消息類型所需的JSON數(shù)據(jù)包如下:
發(fā)送文本消息
{
"touser":"OPENID",
"msgtype":"text",
"text":
{
"content":"Hello World"
}
}
發(fā)送圖片消息
{
"touser":"OPENID",
"msgtype":"image",
"image":
{
"media_id":"MEDIA_ID"
}
}
參數(shù)說(shuō)明
返回碼說(shuō)明
-
代碼實(shí)現(xiàn)
<!-- ih_request.js -->
const request = require('request');
var ih_request = {};
module.exports = ih_request;
ih_request.get = async function(option){
var res = await req({
url: option.url,
method: 'get'
});
res.result?option.success(res.msg):option.error(res.msg);
}
<!-- wx_sendMessage.js -->
var router = require('koa-router')();
const request = require('../script/ih_request');
router.post('/', async function (ctx, next) {
//這個(gè)access_token需要自己維護(hù)
var access_token = 'gOyUImFWLoCWKZfssu9ompMQ7a4UR2npNx4ziHHMMzxjuQzD_XdCQu1UJwcxBQCbUl6owBdRqXk-QjagYzyA5Fb8bgCKuCkO63nKSPwy2ESSYwLoo1bInlg4UMOi2ToGLENaABAATC';
var body = 'success';
console.log(ctx.request.body);
if (ctx.request.body.isCheck){
var checkResult = checkSignature({
'signature' : ctx.request.body.signature,
'timestamp' : ctx.request.body.timestamp,
'nonce' : ctx.request.body.nonce
});
body = checkResult?ctx.request.body.echostr :'err signature';
}else {
var data = JSON.parse(ctx.request.body.data);
switch (data.MsgType){
case 'text': {//用戶在客服會(huì)話中發(fā)送文本消息
await sendTextMessage("我知道了", data, access_token);
break;
}
case 'image': { //用戶在客服會(huì)話中發(fā)送圖片消息
await sendImageMessage(data.MediaId, data, access_token);
break;
}
case 'event': {
console.log('event');
var content = '';
if (data.Event == 'user_enter_tempsession'){ //用戶在小程序“客服會(huì)話按鈕”進(jìn)入客服會(huì)話,在聊天框進(jìn)入不會(huì)有此事件
await sendTextMessage("您有什么問(wèn)題嗎?", data, access_token);
}else if (data.Event == 'kf_create_session'){ //網(wǎng)頁(yè)客服進(jìn)入回話
console.log('網(wǎng)頁(yè)客服進(jìn)入回話');
}
break;
}
}
}
console.log('end');
ctx.body = body;
});
async function sendTextMessage(content, data, access_token){
await request.postJson({
url: 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='+access_token,
body: {
touser:data.FromUserName,
msgtype:"text",
text:
{
content:content
}
},
success: function(res){
console.log(res);
},
error: function(err){
console.log(err);
}
});
}
async function sendImageMessage(media_id, data, access_token){
await request.postJson({
url: 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='+access_token,
body: {
touser:data.FromUserName,
msgtype:"image",
image:
{
media_id:media_id
}
},
success: function(res){
console.log(res);
},
error: function(err){
console.log(err);
}
});
}
4、最后
如何大家看了文章還有不懂或者其他問(wèn)題,歡迎私信我或者評(píng)論