这篇文章讲的很全面: https://blog.csdn.net/u011225099/article/details/76460197
我主要记录下我自己踩的坑。
一、绑定安全域名
在微信公众平台—>公众号设置—>功能设置下面修改js安全域名。
坑1:安全域名不能带http://
域名不是url,不能携带协议部分,所以设置安全域名应该为去掉http://的部分,如果不行还需要将www.也去掉。另外,安全域名不能带端口号。
坑2:分享链接不在安全域名下
我的安全域名设置的xxxx.net,然后分享的页面因为是后端页面,所以携带了端口号,是xxxx.net:8848/index.html,导致分享失败。
这一步没做好,就会疯狂报 invalid url domain 的错。
绕过这两个坑,安全域名就没问题了,下一步就是页面。
二、页面获取签名
签名这块应该是后台处理,如果没处理好,就会报 invalid signature 的错误。
前端请求后台获取签名,需要携带当前页面路径作为参数,因为签名需要这部分参数
坑1:生成签名的参数要和分享之后的路径一样
生成签名时,需要分享路径作为参数,这个路径要和分享之后访问的路径一样,所以需要去掉微信增加的额外参数,即:
var href = location.href.split('#')[0]; //去掉分享后微信增加的路径参数
坑2:wx.config的参数遵循驼峰命名
如果是全干的小伙伴容易中招,因为后端生成签名的参数是全小写,而前端wx.config里面的参数又遵循驼峰命名规则
完整代码如下,详细步骤见注释:
var href = location.href.split('#')[0];
$.getJson('/wxPublic/getSign?url=' + href, function (resp) {
console.log(resp)
wx.config({
debug: true, // 是否开启debug模式,如果开启,每次回调有内容会alert出信息
appId: resp.appId, // 后端返回的公众平台appid
timestamp: resp.timestamp, // 后端返回的时间戳
nonceStr: resp.nonceStr, // 后端返回的随机字符串
signature: resp.signature, // 后端返回的签名
jsApiList: [ // 需要调用的jsApi
'checkJsApi',
'onMenuShareTimeline',//分享到朋友圈
'onMenuShareAppMessage'//分享给微信好友
]
});
wx.ready(function () {
wx.onMenuShareTimeline({ //分享到朋友圈
title: shareTitle, // 分享标题
link: href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: imgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
alert('你还没分享哦')
}
});
wx.onMenuShareAppMessage({ // 分享给朋友
title: shareTitle, // 分享标题
desc: descContent, // 分享描述
link: href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: imgUrl, // 分享图标
type: '', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
alert('你还没分享哦')
}
});
});
wx.error(function (res) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
})
三、后端生成签名
接下来是后端接口获取签名的方式,全干的小伙伴可以看这边:
坑1:appid和appsecret都是微信公众平台的配置
个人在这里坑了最久,因为我这个项目使用了微信网站开放平台,微信app开放平台,一开始都用的那两个平台的appid和appsecret,结果一直提示 invalid url domain 。后来一步步检查才发现项目的公众平台的appsecret都还没申请。
坑2:生成签名要注意的问题
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
第二步,按照要求的规则进行计算签名,这里官方文档要求的是使用sha1加密,所以使用sha1加密获得签名。
这个坑主要报的错就是 invalid signature
完整代码如下,详细步骤见注释:
@GetMapping("/getSign")
@ApiOperation("签名接口")
public ResponseEntity appMsg(String url) throws Exception {
// 时间戳,秒为单位
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
// appid,注意这里是微信公众平台的appid
String appId="";
// appsecret,注意这里是微信公众平台的appsecret
String appsecret="";
// 先获取accessToken,该token有2小时有效期,后续需要对该token做缓存
String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token" +
"?grant_type=client_credential" +
"&appid=" + appid +
"&secret=" + appsecret;
String tokenInfoStr = HttpRequestUtil.httpGet(tokenUrl, null, null);
accessToken = JsonPath.read(tokenInfoStr, "$.access_token");
// 根据token获取jsApiTicket,该ticket有2小时有效期,后续需要对该ticket做缓存
String jsApiUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket" +
"?access_token="+accessToken+"&type=jsapi";
String jsApiJson = HttpRequestUtil.httpGet(jsApiUrl, null, null);
jsApiTicket = JsonPath.read(jsApiJson, "$.ticket");
// 给前端的返回值
Map<String, String> data = new HashMap<>();
data.put("appId", appid);
data.put("nonceStr", WXPayUtil.generateNonceStr());
data.put("timestamp", timestamp);
// 拼接字符串,使用sha1加密获得签名
String params=
"jsapi_ticket="+jsApiTicket+
"&noncestr="+data.get("nonceStr")+
"×tamp="+timestamp+
"&url="+url;
String sign = DigestUtils.sha1Hex(params);
data.put("signatrue", sign);
return ResponseEntity.ok(data);
}