之前做过一次自定义分享,可能碰巧前端没问题,各个参数碰巧都是对的,整个过程很顺利;
可最近做另个微信应用的自定义分享遇到的坑,找了老半天,最终解决,特记录一下;
异常1:config:fail,Error: invalid signature
异常2:updateTimelineShareData:fail the permission value is offline verifying
关于前面错误的,百度了好久,有用信息很少,无力吐槽,很多说加密的url必须和分享的link一致,这个纯属放屁,你分享的link只需要在授权域名下面就ok了,可以是另外的地址,比如我写的就是我微信应用授权地址,别人点击授权完直接访问主页;
首先你的后台加密部分要没有问题,下面的方法才可能帮助到你;
被这两个异常折磨了好久,对于异常一,当时写的过程中,怎么都查都查不出来,去验签平台验签也没问题,分享就是会提示签名错误,现在看来只能是自己对官方文档没细心看,对于这个问题如果你也和我一样,验签没问题,那么明确告诉你,是你的加密时用的url错了(******注意这个加密时用的url必须是你请求页面的url一样,连参数都要带上********);
比如我当前调用后台获取签名的页面是:http://wx.abdfc.com/wxGame/test/result.html?&number=125;那么你后台生成签名加密时用的url也要是这个;页面可以通过
window.location.href.split('#')[0] 方式获取url,传到后台,最后会贴一下我的关键代码
ps:其实遇到这种问题都是,当时开发时进了死胡同,没有真正看清微信开发文档的描述,建议开发时详细查看微信开发文档;
贴一下微信分享接口关于加密部分的说明:
附录1-JS-SDK使用权限签名算法
jsapi_ticket
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。
1.参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):../15/54ce45d8d30b6bf6758f68d2e95bc627.html
2.用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
成功返回如下JSON:
{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}
获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。
签名算法
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
即signature=sha1(string1)。 示例:
noncestr=Wm3WZYTPz0wzccnW
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
timestamp=1414587457
url=http://mp.weixin.qq.com?params=value
步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
步骤2. 对string1进行sha1签名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事项
1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
2.签名用的url必须是调用JS接口页面的完整URL。
3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
如出现invalid signature 等错误详见附录5常见错误及解决办法
对于异常2(updateTimelineShareData:fail the permission value is offline verifying),我个人认为是引入的js版本不对,没有找到相应的函数;
最后贴一下我的代码:
前端页面:(***注:我用的js版本是<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>)
initWeixinAPI(){
var _this = this;
var urld = window.location.href.split('#')[0];
$.ajax({
type: "get",
url: host + "/wxGame/getSignInfo",
data: {
url: urld
},
success: function(data) {
_this.signature = data.signature; // 签名
_this.appId =data.appId; // 应用id
_this.jsapi_ticket =data.jsapi_ticket; // 票据
_this.nonceStr =data.nonceStr; // 随机串
_this.url =data.signature; // 路径
_this.timestamp =data.timestamp; // 时间戳
_this.yaoqing();
},
error: function(e) {
console.log('获取用户信息失败');
}
});
},
yaoqing(){
var _this = this;
_this.isTrue = true;debugger;
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: _this.appId, // 必填,企业号的唯一标识,此处填写企业号corpid
timestamp: _this.timestamp, // 必填,生成签名的时间戳
nonceStr: _this.nonceStr, // 必填,生成签名的随机串
signature: _this.signature,// 必填,签名,见附录1
jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function() {
wx.onMenuShareAppMessage({
title: '我的情商已经满分,你要不要来测一下', // 分享标题
desc: '权威情商测试,帮你清除认识自己', // 分享描述
link:host +'/wxGame/toOauth', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: host+'/wxGame/test/img/logo.png', // 分享图标
success: function () {
vant.Toast('分享成功');
},
cancel: function () {
vant.Toast('取消分享');
}
});
wx.onMenuShareTimeline({
title: '我的情商已经满分,你要不要来测一下', // 分享标题
link: host +'/wxGame/toOauth', // 分享链接,该链接域名必须与当前企业的可信域名一致
imgUrl: host+'/wxGame/test/img/logo.png', // 分享图标
success: function () {
vant.Toast('已分享至朋友圈');
},
cancel: function () {
vant.Toast('取消分享');
}
});
});
后台对应接口实现:(由于我用的后端框架是jfinal,里面集成了微信获取相关票据的接口,我就补贴代码,能看到这里后台逻辑一般没什么问题了,注意一下坑点就行)
public void getSignInfo() {
JsTicket jsApiTicket = JsTicketApi.getTicket(JsTicketApi.JsApiType.jsapi);
String jsapi_ticket = jsApiTicket.getTicket();
String nonce_str = create_nonce_str();
// 注意 URL 一定要动态获取,不能 hardcode.
System.out.println("url>>>>" + url);
String url = getPara("url");
String timestamp = create_timestamp();
// 这里参数的顺序要按照 key 值 ASCII 码升序排序
//注意这里参数名必须全部小写,且必须有序
String str = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + nonce_str +
"×tamp=" + timestamp +
"&url=" + url;
String signature = HashKit.sha1(str);
System.out.println("appId " + ApiConfigKit.getApiConfig().getAppId()
+ " nonceStr " + nonce_str + " timestamp " + timestamp);
System.out.println("url " + url + " signature " + signature);
System.out.println("nonceStr " + nonce_str + " timestamp " + timestamp);
System.out.println(" jsapi_ticket " + jsapi_ticket);
System.out.println("nonce_str " + nonce_str);
setAttr("appId", ApiConfigKit.getApiConfig().getAppId());
setAttr("nonceStr", nonce_str);
setAttr("timestamp", timestamp);
setAttr("url", url);
setAttr("signature", signature);
setAttr("jsapi_ticket", jsapi_ticket);
Map map =new HashMap();
map.put("appId", ApiConfigKit.getApiConfig().getAppId());
map.put("nonceStr", nonce_str);
map.put("timestamp", timestamp);
map.put("url", url);
map.put("signature", signature);
map.put("jsapi_ticket", jsapi_ticket);
renderJson(JsonUtils.toJson(map));
}
以上就是我遇到的问题及解决,希望能帮助到同样遇到问题的你;