接入微信JS-SDK

相关链接:

  1. 微信JS-SDK说明文档

  2. 微信测试号管理

  3. 微信接口调试工具


有一点希望注意:在写代码的时候,要时刻明白写的是前端还是后端。比如某些网页用手机打开,写前端时使用alert调试比较方便,因为浏览器中的console也看不到,特别是在手机端运行时,如果分不清自己写的前后端代码,盯着控制台也是不会有什么输出的。

以下内容均以测试号为例

绑定域名

测试号界面有

  • 测试号信息 appID和appsecret
  • 接口配置信息
  //微信服务器校验 返回echostr才能配置成功
  if (req.query.echostr) {
    console.log('收到微信校验',req.query);
    res.send(req.query.echostr);
    return;
  }
  • JS接口安全域名
  • 模板消息接口
  • 体验接口权限表

绑定域名就是在JS接口安全域名点击修改,修改域名即可

引入js文件

在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js

配置验证信息

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用,通过config接口注入权限验证配置

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

这里有几个重点,

  1. 就是签名生成。
  • 确认签名算法正确签名算法校验
  • 确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。
  • 确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。没有参数,基本应该以/结束 例如:https://www.baidu.com/
  • 确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。
  • 确保一定缓存access_token和jsapi_ticket。例如存入本地JSON文件
  • 用来签名的url要动态生成,否则签名会失效,尤其是分享出去的网页会被添加额外的参数

官方demo找到nodejs的案例,里面有sign.js含有签名算法,把它放到自己的项目中,以供使用。案例中用到的第三方库是哪个版本,如果使用新版本有问题,就用案例中的版本。

//获取token的url地址
var token_url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`;
//获取ticket的url地址
var jsapi_ticket = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${token}&type=jsapi`;

//注意拿到 token和ticket 一定要保存起来,方便后续使用。微信说2个小时 token失效,可以设置个定时器 比如1.8小时请求一次

// 先执行一次
refesh_token_tickte();
// 创建定时器 每隔1.8小时 刷新一次 token 和ticket
var timer = setInterval(refesh_token_tickte,1000 * 60 * 60 *1.8);

/**
 * 获取token和ticket并存储
 */
function refesh_token_tickte() {
    getaccess_token(token_url, getjsapi_ticket);
}

/**
 * 获取token
 * @param {*url} 获取token的url地址 
 * @param {*callback} callback 
 */
function getaccess_token(url, callback) {
  console.log("正在请求token");
  axios
    .get(token_url)
    .then(function(response) {
      if (!response || !response.data || !response.data.access_token) {
        console.log("未获取到token");
        callback(null, null);
        return;
      }
      callback(null, response.data.access_token);
    })
    .catch(function(err) {
      callback(err, null);
    });
}

/**
 * 回调函数 
 * 根据token获取jsapi_ticket
 * 同时 会生成 签名 并保存到本地
 * @param {*} err 
 * @param {*} token 
 */
function getjsapi_ticket(err, token) {
  if (err || !token) {
    console.log("获取token失败");
    return;
  }
  var jsapi_ticket = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${token}&type=jsapi`;
  axios
    .get(jsapi_ticket)
    .then(function(response) {
      if (!response || !response.data || !response.data.ticket) {
        console.log("未获取到jsapi_ticket", response.data.errmsg);
        return;
      }
      //只存储签名
      try {
          var signjson = "./serverjs/sign.json";
        jsonfile.writeFileSync(signjson, {
            access_token:token,
            jsapi_ticket:response.data.ticket
        }, { spaces: 2 });
        console.log("token写入成功");
      } catch (error) {
        console.log("写入文件失败", error.message);
      }

    })
    .catch(function(error) {
      if (error) {
        console.log("获取jsapi_ticket失败", error.message);
      }
    });
}
/**
 * 根据url动态生成签名
 * @param {*configurl} url 
 */
function createCoinfDynamic(url) {
    console.log('要配置的url是',url);
  try {
    //1. 从文件中读取 ticket
    var signinfo = jsonfile.readFileSync(signjson);
    var ticket = signinfo.jsapi_ticket;
    var token = signinfo.access_token;
    //2. 生成签名
    //sign 是引入的sign.js中的函数
    var signature = sign(ticket, url);
    //3. 补充参数 并返回
    signature.appId = appid;
    signature.jsApiList = [
      "chooseImage",
      "uploadImage",
      "getNetworkType",
      "onMenuShareTimeline",
      "onMenuShareAppMessage",
      "hideMenuItems",
      "checkJsApi"
    ];
    signature.token = token;
    return signature;
  } catch (err) {
    console.log("动态生成签名出错",err.message);
    return null;
  }
}

我的url也不是动态生成的,我是收到客户端请求时,生成一个网页,在网页中向服务器发起请求,拿到配置信息,然后去注册。看起来很麻烦,但是工作正常。

router.get('/wechatconfig',function (req,res) {
// 获取微信注册配置信息
  var requesturl = req.url;
  var configurl = requesturl.split("xxconfigurl=")[1].split('#')[0];
  var config = get_config(configurl);
  res.send(config);
});

我本来想的是,收到请求时,直接生成配置信息,然后传递给网页,到时候网页不用向服务端请求,直接就拿到数据了。我用的是ejs模板,的确可以把数据传递过去,但是拿到的数据会有转码,我已经<%- %>但似乎还是不行。所以最后还是用的之前的方法。
因为刚接触这些,应该是用后台数据渲染网页时,掌握的不好。不知道用vue可不可以完成服务器把数据带到网页中。

  1. 接口列表

    像朋友圈是 onMenuShareTimeline 而不是 menuItem:share:appMessage,千万不要写错了,
    写错了就不能响应事件。

  2. 微信的事件最好放在ready里面

wx.ready(function(){
    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。

//分享到朋友圈的事件
wx.onMenuShareTimeline({
    title: '', // 分享标题
    link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
    imgUrl: '', // 分享图标
    success: function () { 
        // 用户确认分享后执行的回调函数
    },
    cancel: function () { 
        // 用户取消分享后执行的回调函数
    }
});

});

你可能感兴趣的:(接入微信JS-SDK)