相关链接:
有一点希望注意:在写代码的时候,要时刻明白写的是前端还是后端。比如某些网页用手机打开,写前端时使用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
});
这里有几个重点,
- 就是签名生成。
- 确认签名算法正确签名算法校验
- 确认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可不可以完成服务器把数据带到网页中。
-
接口列表
像朋友圈是 onMenuShareTimeline 而不是 menuItem:share:appMessage,千万不要写错了,
写错了就不能响应事件。 微信的事件最好放在ready里面
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
//分享到朋友圈的事件
wx.onMenuShareTimeline({
title: '', // 分享标题
link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: '', // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
});