使用场景
小程序里,只能是用户发起form请求,才能被动收到1次或3次通知,比如支付,发货的通知,因此有客户下单,作为管理员收不到消息推送的,必须要时不时地看一下web后台订单管理很不方便,于是借道服务号的模板消息,向指定用户(即管理员)推送来单了的消息。本文的初衷就是为了解决这个无奈的。
解题思路
1.在小程序后台生成一个二维码,带着appid的参数,生成链接地址,例如https://mp.it577.net/bind?appid=wx15***pq 2.扫一扫拿到上述的参数进入服务号体系,取得操作人即web后台管理员的openid 3.将openid与appid相关联 4.小程序中有用户在就向公众号暴露的发起推送指令,例如https://mp.it577.net/message/push?appid=wx15***pq 5.公众号接收到指令向管理员的openid推送订单模板信息
步骤
一、创建了数据库,使用express-generator脚手架生成应用
1.服务号api体系 1.1 bind (appid),其中appid由二维码参数得到,其中openid进入服务号时自然获得 1.2 pushMessage (appid,templateid,data) 2.小程序api体系 1.1 payment回调成功,即用户付款成功之后,向服务号api调用pushMessage接口
小程序web后台代码
1.创建二维码
这里使用一个第三方module,qr-image
详情用法如下
var {bindUrl} = require('../utils/config');
var qr = require('qr-image');
try {
var img = qr.image(bindUrl, {size :5});
res.writeHead(200, {'Content-Type': 'image/png'});
img.pipe(res);
} catch (e) {
res.writeHead(414, {'Content-Type': 'text/html'});
res.end('<h1>414 Request-URI Too Large</h1>');
}
服务号代码
1.公众号管理后台绑定可信域名
2.请求服务号网页授权登录接口
3.代码描述
router.get('/auth', function(req, res) {
var REDIRECT_URI = encodeURI(req.protocol + '://' + req.headers.host + req.originalUrl.replace(req.url, '') + '/code');
console.log(REDIRECT_URI);
var obj = {
appid: mp.APPID,
redirect_uri: REDIRECT_URI,
response_type: 'code',
scope: 'snsapi_userinfo',
state: req.query.appid
};
var param = querystring.stringify(obj);
var url = `https://open.weixin.qq.com/connect/oauth2/authorize?${param}`;
console.log(url);
res.redirect(url);
});
router.get('/code', function(req, res) {
console.log("req.query");
console.log(req.query.code);
var obj = {
appid: mp.APPID,
secret: mp.SECRET,
code: req.query.code,
grant_type: 'authorization_code'
};
var appid = req.query.state;
var param = querystring.stringify(obj);
var url = `https://api.weixin.qq.com/sns/oauth2/access_token?${param}`;
request(url, function(error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
if (!body.errcode) {
var data = JSON.parse(body);
console.log(data);
data = _.extend(data, {appid: appid});
// 获取粉丝信息
var infoUrl = `https://api.weixin.qq.com/sns/userinfo?access_token=${data.access_token}&openid=${data.openid}&lang=zh_CN`;
request(infoUrl, function (error, response, body) {
console.log(infoUrl)
console.log(body)
data = _.extend(data, JSON.parse(body));
// 判断是否已经存在
Customer.findOneAndUpdate(_.pick(data, 'openid appid'), data, {upsert: true}, (err, result) => {
if (err) {
console.log(err);
}
res.render('success');
});
});
}
});
});
以上代码共完成了3部分操作:1.请求code,2.取出用户openId,3.绑定openId与小程序appid
3.小程序有用户下单支付向服务器请求推送模块消息
首先,创建服务号的模板消息,注意,这里并不是小程序的模板消息。
依然获得了data格式如下
{{first.DATA}}
订单编号:{{keyword1.DATA}}
客户昵称:{{keyword2.DATA}}
订单价格:{{keyword3.DATA}}
订单标题:{{keyword4.DATA}}
订单截止时间:{{keyword5.DATA}}
{{remark.DATA}}
接下来,在服务号创建被暴露一个message/push接口,供用户支付成功被调用
// 推送消息
router.post('/push', function(req, res) {
// 使用querystring来格式化query字符串
var url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${mp.APPID}&secret=${mp.SECRET}`;
console.log(url);
request(url, function(error, response, body) {
var access_token = JSON.parse(body).access_token;
// 请求模板消息接口
var messageUrl = `https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=${access_token}`;
// 通过appid反查openid
Customer.findOne({
appid: req.body.appid
}, (err, customer) => {
if (err) {
console.log(err);
}
// 用户id
var openid = customer.openid;
//
var data = {
"touser": openid,
"template_id": "8_Vlmaf3EpW4fu-u94yTwHUurQWsymvdBxM-lsHZBTM",
"url": req.body.url,
"data": {
"first": {
"value": "来新订单了",
"color": "#173177"
},
"keyword1": {
"value": req.body.title,
"color": "#173177"
},
"keyword2": {
"value": moment.full(req.body.createdAt),
"color": "#173177"
},
"keyword3": {
"value": req.body.address,
"color": "#173177"
},
"keyword4": {
"value": req.body.nickname,
"color": "#173177"
},
"keyword5": {
"value": "已支付",
"color": "#173177"
},
"remark": {
"value": "请登录后台查看",
"color": "#173177"
}
}
};
request({
url: messageUrl,
method: "POST",
json: true,
body: data
},
function(error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
}
);
});
});
res.send('push message success');
});
顺带提一句,querystring这个第三方module很好用,将对象转成?name=huangxj&age=30这样的字符串
结尾
经过这样的操作,就完成了借道服务号完成向小程序管理员推送消息的任务。以上思路来自于Bmob的消息推送机制,还有粉丝【是我没跑】的提点。
另辟蹊径
以上是通过软方式解决,还有一种是通过市面上云打印机的硬方案,用户下单,直接给打印推单子,机子直接吐小票,更要干脆利落。