微信分享效果
此类文档网上很多,bug解决了小半天,踩坑之后记录下来.
原理
原理是接入微信js-api,步骤如下:
secret
以及appid
换取access_tooken
(在服务器保存,有效期7200秒)
用access_tooken
换取jsapi_ticket
(在服务器保存,有效期7200秒)
用jsapi_ticket
在前端页面进行初始化以及参数准备
其中1和2采用方式: 心跳node-schedule库
存储方式:fs文件写入(如果需要可以mysql存储)
目的
实现以前分享只显示自动抓取的网站标题和网址,图片默认第一张
实现以后可以自定义分享的标题,简介以及图片,并且可以使用回调
心跳换取access_tooken
和jsapi_ticket
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| const request = require(`request`); const schedule = require('node-schedule'); const fs = require(`fs`); const path = require(`path`); const moment = require(`moment`);
const appid = `appid`; const secret = `secret`;
let access_token = ``; let jsapi_ticket = ``; let timestamp = moment().unix();
const writeFile = () => { request.get(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`,(err,response,body)=>{ if(err){ return console.log(err); }else{ console.log('获取access_token之body' , body ); access_token = JSON.parse(body).access_token; console.log('access_token',access_token); request.get(`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`,(err,response,body)=>{ if(err){ return console.log(err); }else{ console.log('获取获取jsapi_ticket之body' , body ); jsapi_ticket = JSON.parse(body).ticket; console.log('获取jsapi_ticket',jsapi_ticket); let ready_data = {}; ready_data.access_token = access_token?access_token:''; ready_data.jsapi_ticket = jsapi_ticket?jsapi_ticket:''; ready_data.timestamp = timestamp?timestamp:''; fs.writeFile(path.join(__dirname, 'access_token_ticket.txt'), JSON.stringify(ready_data) , function (err) { if (err) { return console.log(err); }else{ console.log("写入文件成功"); } }); } }); } }); }
writeFile();
var rule = new schedule.RecurrenceRule(); rule.hour = [0,2,4,6,8,10,12,14,16,18,20,22]; rule.minute = 0; rule.second = 0; var j = schedule.scheduleJob(rule, function(){ console.log('现在时间:',new Date()); writeFile(); });
|
服务器用来提供jsapi_ticket
的接口
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 37 38 39 40
| const crypto = require(`crypto`); const uuid = require(`uuid`); const appid = `appid`; const fs = require(`fs`); const path = require(`path`);
let access_token = ``; let jsapi_ticket = ``; let timestamp; router.post(`/getwxtooken`,async (req,res,next)=>{ await fs.readFile(path.join('/usr/local/workspaceThomas/getwxtookenforxntywebsite/', 'access_token_ticket.txt'),{encoding:'utf-8'}, async function(err,bytesRead) { if (err) { console.log( err ); }; var data = await JSON.parse(bytesRead); access_token = await data?data.access_token:data.access_token; jsapi_ticket = await data?data.jsapi_ticket:data.jsapi_ticket; timestamp = await data?data.timestamp:parseInt(data.timestamp); });
let noncestr = uuid.v1(); let url = req.body.url; let string1 = await `jsapi_ticket=${jsapi_ticket}&noncestr=${noncestr}×tamp=${timestamp}&url=${url}`; var sha1 = await crypto.createHash("sha1"); await sha1.update(string1); var signature = await sha1.digest("hex");
res.send({ appid: appid, access_token: access_token, noncestr: noncestr, jsapi_ticket: jsapi_ticket, timestamp: timestamp, url: url, string1: string1, signature: signature });
});
|
这里需要注意的是加密时的字符串拼接是由顺序的ASCII从小到大顺序,官方文档有相关说明
如果提示签名非法请按照官方文档从上至下排查
建议将async和await替换成Promise
前端进行的操作
先引入官方js
1
| <script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
|
初始化
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| $(function() { $.ajax({ "url":"jszhai.cn", "type":"post", "dataType":"json", "data":{"url": location.href.split('#')[0]}, "success":function(data){ wxstart(data, ""); console.log( data ); } }); });
function wxstart(data, url){ var url = location.href.split('#')[0]; var appId = data.appid; var timestamp = data.timestamp; var nonceStr = data.noncestr; var signature = data.signature; wx.config({ debug: false, appId: appId, timestamp: timestamp, nonceStr: nonceStr, signature: signature, jsApiList: ["onMenuShareTimeline", "onMenuShareAppMessage", "onMenuShareQQ"] });
wx.ready(function(){ var imgurl = $('.art_titu').find('img').attr('src'); var title = document.title; var desc = $('.art_main').text().replace(/\s+/g,'');; wx.onMenuShareTimeline({ title: title, desc: desc, link: url, imgUrl: imgurl, success: function () { alert('分享到朋友圈成功!'); }, cancel: function () { alert('您已取消分享到朋友圈!'); } });
wx.onMenuShareAppMessage({ title: title, desc: desc, link: url, imgUrl: imgurl, type: '', dataUrl: '', success: function () { alert('分享给微信好友成功!'); }, cancel: function () { alert('取消分享成功!'); } });
wx.onMenuShareQQ({ title: title, desc: desc, link: url, imgUrl: imgurl, success: function () { alert('成功分享给QQ好友!'); }, cancel: function () { alert('取消分享到QQ成功!'); } }); }); }
|