微信分享效果
此类文档网上很多,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
| 12
 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的接口
| 12
 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>
 | 
初始化
| 12
 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成功!');
 }
 });
 });
 }
 
 |