本文是微信公众号开发-H5网页分享功能的前、后端整个流程,以及遇到的invalid signature问题的解答,希望对该功能开发不是很清楚的朋友有所帮助。
一、准备工作。
百度下“微信 公众平台 开发 文档”进入官方接口文档(这里有朋友要问了,为什么搜索的时候要在词与词之间加空格,这是个小技巧,这样搜索的结果更加准确):文档1.1至3.7的篇幅清晰的介绍了如何设置JS安全域名、网站如何导入开放的js接口文件、如何签名验证和以及分享的多种类型。大家还是要仔细的阅读下。
1、绑定安全域名:因为调用微信H5网页分享功能需要调用微信开放的JS接口,并且网站的域名要绑定到微信公众平台“JS接口安全域名”下,才能正常调用微信开放的JS接口。比如网站是http://my.csdn.com/index.html,那么JS接口安全域名就是my.csdn.com。域名绑定失败或者域名不存在会报错误:invalid url domain。
2、引入微信js文件:在需要调用JS接口的页面引入JS文件,用script标签引入即可,可以直接引用官方提供的JS链接,也可以把JS文件下载到本地引用。
3、通过config接口注入权限验证配置:
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用JS-SDK接口。wx.config调用方法如下:
config接口调用完后就可调用ready接口和error接口,这2个接口是代表config是否验证成功的。分享的功能可以封装到一个方法中,然后在ready接口中进行调用。下面直接放代码。
二、前端代码
<script src="js/jquery-3.2.1.js"></script>
<script src="js/jweixin-1.4.0.js"></script>
<script src="js/getRequestParam.js"></script>
<script type="text/javascript">
var nonceStr = ''; //后台返回-生成签名的随机串
var timestamp = '';//后台返回-生成签名的时间戳
var signature = '';//后台返回-签名
var CurrentPageUrl = '';//前台获取传递给后台(后台签名时用到)-当前页面地址,包括url后面接的参数,如果是微信静默授权进来的,该地址会包含微信Code等信息
//微信公众平台APPID
var WX_APPID = "wx8xxxcb598xx5930f";
//后台接口地址
var Api_ROOT = "http://localhost:61101/";
//页面逻辑控制类
var center = {
//网页分享方法
WxShare: function (s_timestamp, s_nonceStr, s_signature, s_title, s_des, s_imgUrl, CurrentPageUrl) {
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: WX_APPID, // 必填,公众号的唯一标识
timestamp: s_timestamp, // 必填,生成签名的时间戳【后台返回】
nonceStr: s_nonceStr, // 必填,生成签名的随机串【后台返回】
signature: s_signature,// 必填,签名【后台返回】
jsApiList: [
'checkJsApi', //判断当前客户端版本是否支持指定JS接口
'onMenuShareTimeline', //分享给好友
'onMenuShareAppMessage', //分享到朋友圈
'onMenuShareQQ', //分享到QQ
'onMenuShareWeibo',//分享到微博<br/>
'onMenuShareQZone'
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
//通过ready接口处理成功验证
wx.ready(function () {
//alert("wx.ready:" + timestamp);
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
wxready();
});
//通过error接口处理失败验证
wx.error(function (res) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
alert("res错误信息:" + res.errMsg);
});
function wxready() {
// 判断当前版本是否支持指定 JS 接口,支持批量判断
wx.checkJsApi({
jsApiList: [
'checkJsApi', //判断当前客户端版本是否支持指定JS接口
'onMenuShareTimeline', //分享给好友
'onMenuShareAppMessage', //分享到朋友圈
'onMenuShareQQ', //分享到QQ
'onMenuShareWeibo',//分享到微博<br/>
'onMenuShareQZone'//分享到QQ空间
],
success: function (res) {
alert("ok");
}
});
debugger;
var url = CurrentPageUrl;///分享链接,该链接域名在对应的公众号JS安全域名列表中配置过才行
var title = s_title;
var desc = s_des;
var imgUrl = s_imgUrl;
//分享到朋友圈
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: '', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
// 用户确认分享后执行的回调函数
alert("已分享");
},
cancel: function () {
// 用户取消分享后执行的回调函数
alert("已取消分享");
}
});
//分享到QQ
wx.onMenuShareQQ({
title: title, // 分享标题
desc: desc, // 分享描述
link: url, // 分享链接
imgUrl: imgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
alert("已分享");
},
cancel: function () {
// 用户取消分享后执行的回调函数
alert("已取消分享");
}
});
//分享到腾讯微博
wx.onMenuShareWeibo({
title: title, // 分享标题
desc: desc, // 分享描述
link: url, // 分享链接
imgUrl: imgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
alert("已分享");
},
cancel: function () {
// 用户取消分享后执行的回调函数
alert("已取消分享");
}
});
//分享到QQ空间
wx.onMenuShareQZone({
title: title, // 分享标题
desc: desc, // 分享描述
link: url, // 分享链接
imgUrl: imgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
alert("已分享");
},
cancel: function () {
// 用户取消分享后执行的回调函数
alert("已取消分享");
}
});
}
},
//调用后台接口返回数据方法
GetActivityInfo: function (aid, PageUrl) {
$.ajax({
url: Api_ROOT + '/Activity/GetActivitysInfo',
datatype: "JSON",
data: { "ActivitysId": aid, "h5PageUrl": PageUrl },
async: false,
type: 'post',
success: function (data) {
nonceStr = data.Data.ShareModelInfo.nonceStr;//后台返回-生成签名的随机串
timestamp = data.Data.ShareModelInfo.timestamp;//后台返回-生成签名的时间戳
signature = data.Data.ShareModelInfo.signature;//后台返回-签名
center.WxShare(timestamp, nonceStr, signature, data.Data.ActivityInfo.AcTitle, data.Data.ActivityInfo.AcInfo, data.Data.ActivityInfo.AdUrl, PageUrl);
}
})
},
}
//页面函数入口
$(function () {
//活动ID
var ActivitysId = request('Aid');
//当前页面地址,包括url后面接的参数,如果是微信静默授权进来的,该地址会包含微信Code等信息
CurrentPageUrl = location.href.split('#')[0];
//通过活动ID调用接口返回活动详情信息
center.GetActivityInfo(ActivitysId, CurrentPageUrl);
});
</script>
三、后台代码
四、关于“invalid signature”签名验证失败需要注意的点。
一般出现这个错误多半是后台签名获取有问题,主要原因有以下几点:
1、APPID和APPSECRET填错
这个错误可以到官方的调试页面获取access_token看看是否是正确,点击获取获取access_token
根据返回的结果可以判断页面内的APPID和APPSECRET有没有出错,没有出错的话可以点击获取jsapi_ticket
利用前面拿到的access_token 采用http GET方式请求获得jsapi_ticket,如果出错的话会返回对应的说明。
2、超过了每日的access_token获取上限
官方限定每日2000次请求,所以如果没有缓存access_token的话,还是比较容易过限的。
3、确认config中nonceStr
H5页面中的wx.config方法里nonceStr参数中的S是大写的。
4、确认url是页面完整的url
请在当前页面alert(location.href.split('#')[0])确认,包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。
大部分的人最主要的问题还是在第4点,后台用url做签名时不要自己定义url,最好是前端每次请求接口时把url通过location.href.split('#')[0] 获取后传进来,注意后台接收这个参数数打印以下跟前端的location.href.split('#')[0] 进行对比,看是否一致,不一致可能需要用encodeURIComponent 进行编码后再传给后台。