предисловие
Мы знаем, что страница H5 часто должна перенаправлять пользователей в приложение и перенаправлять трафик, загружая установочный пакет или переходя в App Store/Appstore. Однако, поскольку доменное имя должно быть проверено, когда апплет встраивает веб-просмотр, невозможно перенаправить трафик на сторонний рынок приложений и Appstroe. тогда что нам делать? Можно только сказать, что один фут выше одного фута, а апплет Weibo — как перенаправить трафик:
Способ спасти страну через кривую, используя онлайн-функцию апплета, вы можете открыть путь H5 для загрузки и руководства. Таким образом, вводится тема этого документа, функция автоматического ответа онлайн-обслуживания клиентов апплета. 😆
Прежде чем читать этот документ, лучше всего ознакомиться с официальными документами по обслуживанию клиентов Мини-программы:
1.Руководство пользователя сообщений службы поддержки клиентов
2.Мини-программа Интерфейс сервера сообщений службы поддержки клиентов
3.Документация по разработке сообщений службы поддержки клиентов
На этот раз разработка функции онлайн-обслуживания клиентов также наступила на множество ям, и я также ознакомился с большим количеством информации в Интернете, но большая часть фона основана на php или python, разработке java, node. js меньше, поэтому на этот раз запишите процесс для справки, чтобы никто не наступил на яму. Могут быть некоторые ошибки, добро пожаловать на исправление и обмен. Кроме того, используемый нами фреймворк узла является самоинкапсулированным на основе koa и будет отличаться от других фреймворков некоторыми деталями, поэтому нет необходимости запутываться.
Описание требования
type | содержание |
---|---|
text | Текст = текстовый ответ контент |
link | title=заголовок description=url описания=ссылка перехода thumb_url=адрес изображения |
image | imageurl=URL-адрес изображения |
- После того, как пользователь требует точного соответствия условию ответа, прежде чем вы получите автоматический ответ
- Поддержка нескольких ключей и соответствующий ответ
- Ответы, отличные от настроенного ключа, можно настроить автоматический ответ по умолчанию.
Процесс развития
Напишите кнопку для перехода в службу поддержки
index.wxml
<button open-type="contact">转在线客服</button>
Фоновая конфигурация
Авторизоватьсяфон апплетаПосле «Разработчик» — «Настройки разработки» — «push-уведомления» администратор сканирует код для включения службы сообщений, заполняет адрес сервера (URL), токен (Token) и ключ шифрования сообщения (EncodingAESKey) и другую информацию.
- URL-адрес сервера
URL-адрес: URL-адрес интерфейса, используемый разработчиками для получения сообщений и событий WeChat. URL-адрес, введенный разработчиком, должен начинаться с http:// или https://, что поддерживает порты 80 и 443 соответственно.
Важно помнить, что адрес сервера должен бытьонлайнАдрес, потому что сервер WeChat должен быть доступен. Адресы Localhost, IP и INTRATENT не являются приемлемыми.
Это ведет кНу, простыми словами, это настроить доменное имя в сети, но это доменное имя может проникнуть на настроенный вами локальный адрес разработки, что упрощает вам отладку и просмотр логов. Рекомендуется инструмент, который может обеспечить проникновение в интрасеть. (не реклама 😆)
NATAPPПодробности не приводятся, чтобы не заподозрить в рекламе.
Проще говоря, у NATAPP есть два режима: бесплатный и платный.Бесплатный заключается в том, что доменное имя время от времени меняется.Это немного экстравагантно для конфигурации push-сообщений WeChat, иметь только три возможности измениться в месяц. В какой-то момент настроенное доменное имя становится недоступным, и его необходимо перенастроить. Плата взимается за фиксированное доменное имя, а сопоставленный адрес интрасети также можно изменить в любое время. Хозяин перешел с бесплатного на платный режим, а месяц использования VIP составляет около десяти юаней.
2.Token
Токен можно написать небрежно, но запомните его, потому что вам нужно использовать его в интерфейсе.
3.EncodingAESKey
Он может быть сгенерирован случайным образом.
4. Метод шифрования и формат данных
Выберите в соответствии с вашими предпочтениями режим безопасности и формат JSON, выбранные арендодателем. Различные модели и форматы данных будут отличаться в разработке, и вы должны измерить сами. Теперь, когда эти конфигурации понятны, давайте начнем программировать.
Убедитесь, что сообщение действительно отправлено с сервера WeChat.
Прежде чем конфигурация будет отправлена, вам нужно написать в интерфейсе, что проверочное сообщение приходит с сервера WeChat.
server.js
/*
* https://developers.weixin.qq.com/miniprogram/dev/framework/server-ability/message-push.html
* 验证消息的确来自微信服务器
* 开发者通过检验 signature 对请求进行校验(下面有校验方式)。
* 若确认此次 GET 请求来自微信服务器,请原样返回 echostr 参数内容,
* 则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:
* 将token、timestamp、nonce三个参数进行字典序排序
* 将三个参数字符串拼接成一个字符串进行sha1加密
* 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
*/
const crypto = require('crypto');
async wxCallbackAction(){
const ctx = this.ctx;
const method = ctx.method;
//微信服务器签名验证,确认请求来自微信
if(method === 'GET') {
// 1.获取微信服务器Get请求的参数 signature、timestamp、nonce、echostr
const {
signature,
timestamp,
nonce,
echostr
} = ctx.query;
// 2.将token、timestamp、nonce三个参数进行字典序排序
let array = ['yourToken', timestamp, nonce];
array.sort();
// 3.将三个参数字符串拼接成一个字符串进行sha1加密
const tempStr = array.join('');
const hashCode = crypto.createHash('sha1'); //创建加密类型
const resultCode = hashCode.update(tempStr, 'utf8').digest('hex');
// 4.开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
if (resultCode === signature) {
console.log('验证成功,消息是从微信服务器转发过来');
return this.json(echostr);
}else {
console.log('验证失败!!!');
return this.json({
status: -1,
message: "验证失败"
});
}
}
}
После разработки интерфейса проверки можно отправить фоновую конфигурацию. Если конфигурация прошла успешно, вам будет предложено следующее:
Получение и отправка сообщений
Когда пользователь отправляет сообщение в сеансе обслуживания клиентов или некоторые определенные действия пользователя вызывают отправку события, сервер WeChat отправляет сообщение или пакет события на 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');
}
}
//处理微信回调消息的总入口 (只处理了文本类型,其他类型自行添加)
async _handleWxMsg(msgJson){
if(!msgJson){
return ;
}
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
документ расшифровки шифрования сообщения
const crypto = require('crypto'); // 加密模块
const decodePKCS7 = function (buff) {
let pad = buff[buff.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return buff.slice(0, buff.length - pad);
};
// 微信转发客服消息解密
const decryptContact = (key, iv, crypted) => {
const aesCipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
aesCipher.setAutoPadding(false);
let decipheredBuff = Buffer.concat([aesCipher.update(crypted, 'base64'), aesCipher.final()]);
decipheredBuff = decodePKCS7(decipheredBuff);
const lenNetOrderCorpid = decipheredBuff.slice(16);
const msgLen = lenNetOrderCorpid.slice(0, 4).readUInt32BE(0);
const result = lenNetOrderCorpid.slice(4, msgLen + 4).toString();
return result;
};
// 解密微信返回给配置的消息服务器的信息
const decryptWXContact = (wechatData) => {
if(!wechatData){
wechatData = '';
}
//EncodingAESKey 为后台配置时随机生成的
const key = Buffer.from(EncodingAESKey + '=', 'base64');
const iv = key.slice(0, 16);
const result = decryptContact(key, iv, wechatData);
const decryptedResult = JSON.parse(result);
console.log(decryptedResult);
return decryptedResult;
};
module.exports = decryptWXContact;
Код вызова - код наконец закончен, чтобы увидеть эффект:
Суммировать
В разработке не все шло гладко, и были некоторые подводные камни, о которых стоит упомянуть.
-
uploadTempMedia
media
FormData использует формат данных параметра (с узломrequest
Библиотеки просты в реализации.urllib
В этой библиотеке есть ямы и ямы, все слезы Т_Т) - Не забудьте вернуть сообщение независимо от успеха или неудачи
success
, в противном случае, даже если ответное сообщение успешно получено и журнал не сообщает об ошибке, IOS подскажет, что служба, предоставляемая апплетом, не удалась.Пожалуйста, повторите попытку позже.
использованная литература
Новости службы поддержки Access Access Applet KOA
Блог-центр Renrendai Big Front-end Technology
Наконец-то прорекламировали. Добро пожаловать в гостиБлог-центр Renrendai Big Front-end Technology
внутри оnodejs
react
reactNative
Небольшие программы, фронтенд-инжиниринг и другие сопутствующие технические статьи обновляются одна за другой. Добро пожаловать в гости и жалуйтесь~