当用户在客服会话发送消息、或由某些特定的用户操作引发事件推送时,微信服务器会将消息或事件的数据包发送到开发者填写的 URL。开发者收到请求后可以使用 发送客服消息 接口进行异步回复。
本文以接收文本消息为例开发:
server.js
const WXDecryptContact = require('./WXDecryptContact'); async wxCallbackAction(){ const ctx = this.ctx; const method = ctx.method; //接收信息时 为POST请求;(完整代码自行与上面验证时的合并即可) if(method === 'POST'){ const { Encrypt } = ctx.request.body; //配置时选的安全模式 因此需要解密 if(!Encrypt){ return this.json('success'); } const decryptData = WXDecryptContact(Encrypt); await this._handleWxMsg(decryptData); return this.json('success'); }else{ return this.json('success'); } } //处理微信回调消息的总入口 (只处理了文本类型,其他类型自行添加) async _handleWxMsg(msgJson){ if(!msgJson){ return this.json('success'); } const { MsgType } = msgJson; if(MsgType === 'text'){ await this._sendTextMessage(msgJson); } } //微信文本信息关键字自动回复 async _sendTextMessage(msgJson){ //获取CMS客服关键词回复配置 const result = await this.callService('cms.getDataByName', 'wxApplet.contact'); let keyWordObj = result.data || {}; //默认回复default let options = keyWordObj.default; for(let key in keyWordObj){ //查看是否命中配置的关键词 if(msgJson.Content === key){ //CMS配置项 options = keyWordObj[key]; } } } //获取access_token const accessToken = await this._getAccessToken(); /* * 先判断配置回复的消息类型是不是image类型 * 如果是 则需要先通过 新增素材接口 上传图片文件获得 media_id */ let media_id = ''; if(options.type === 'image'){ //获取图片地址(相对路径) let url = options.url; const file = fs.createReadStream(url); //调用微信 uploadTempMedia接口 具体实现见 service.js const mediaResult = await this.callService('wxApplet.uploadTempMedia', { access_token: accessToken, type: 'image' }, { media: file } ); if(mediaResult.status === 0){ media_id = mediaResult.data.media_id; }else { //如果图片id获取失败 则按默认处理 options = keyWordObj.default; } } //回复信息给用户 const sendMsgResult = await this.callService('wxApplet.sendMessageToCustomer', { access_token: accessToken, touser: msgJson.FromUserName, msgtype: options.type || 'text', text: { content: options.description || '', }, link: options.type === "link" ? { title: options.title, description: options.description, url: options.url, thumb_url: options.thumb_url } : {}, image: { media_id } } ); }
service.js
const request = require('request'); /* * 获取CMS客服关键词回复配置 * 这个接口只是为了回去CMS配置的字段回复关键字配置 返回的data数据结构如下 */ async contact(){ return { data: { "1": { "type": "link", "title": "点击下载[****]APP", "description": "注册领取领***元注册红包礼", "url": "https://m.renrendai.com/mo/***.html", "thumb_url": "https://m.we.com/***/test.png" }, "2": { "url": "http://m.renrendai.com/cms/****/test.jpg", "type": "image" }, "3": { "url": "/cms/***/test02.png", "type": "image" }, "default": { "type": "text", "description": "再见" } } } } /* * 把媒体文件上传到微信服务器。目前仅支持图片。用于发送客服消息或被动回复用户消息。 * https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/customer-message/customerServiceMessage.uploadTempMedia.html */ async uploadTempMedia(data,formData){ const url = `https://api.weixin.qq.com/cgi-bin/media/upload?access_token=${data.access_token}&type=${data.type}`; return new Promise((resolve, reject) => { request.post({url, formData: formData}, (err, response, body) => { try{ const out = JSON.parse(body); let result = { data: out, status: 0, message: "ok" } return resolve(result); }catch(err){ return reject({ status: -1, message: err.message }); } }); } } /* * 发送客服消息给用户 * https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/customer-message/customerServiceMessage.send.html */ async sendMessageToCustomer(data){ const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${data.access_token}`; return new Promise((resolve, reject) => { request.post({url, data}, (err, response, body) => { ... }); } }
WXDecryptContact.js