最近写的微信分享功能,调试一个签名就用了一天时间,主要还是微信的API有点难看得懂吧!主要是调用JS-SDK时,生成签名花费了很长时间调试,到最后才发现原来是原来是自己配置做错了。
先看看官方的JS-SDK使用步骤:
步骤一:绑定域名
步骤二:引入JS文件
1、获取access_token(普通的access_token),通过access_token获取jsapi_ticket,主要注意的是,jsapi_ticket和access_token每一天都是有使用次数限制的,超时时间是7200s,所以在使用的时候需要保存到全局变量或者数据库或者是redis等,并且需要写一个定时器,在7200s后重新获取这两个值,刷新到保存的区域中;以下是我获取access_token的方法:
public AccessToken getAccessToken(@Context HttpServletRequest req, @Context HttpServletResponse resp) throws ClientProtocolException, IOException{
HttpSession httpSession = req.getSession();
AccessToken token = new AccessToken();
String url = ACCESS_TOKEN_URL;
JSONObject jsonObject = WeiXinUtil.doGetStr(url);//使用刚刚写的doGet方法接收结果
if(jsonObject!=null){ //如果返回不为空,将返回结果封装进AccessToken实体类
token.setToken(jsonObject.getString("access_token"));//取出access_token
token.setExpiresIn(jsonObject.getInt("expires_in"));//取出access_token的有效期
httpSession.setAttribute("access_token", token.getToken());
System.out.println("授权获取的token==="+jsonObject.getString("access_token"));
Contants.ACCESS_TOKEN=jsonObject.getString("access_token");
Contants.token_expires_in=jsonObject.getInt("expires_in");
}
return token;
}
2、获取jsapi_ticket的主要实现方法如下:
public void getJsapi_ticket(@Context HttpServletRequest req, @Context HttpServletResponse resp) throws ClientProtocolException, IOException{
String access_token=Contants.ACCESS_TOKEN;
System.out.println("access_token==="+access_token);
String url="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+access_token+"&type=jsapi";
JSONObject jsonObject=WeiXinUtil.doGetStr(url);
System.out.println(jsonObject);
String ticket=jsonObject.getString("ticket");
Contants.JSAPI_TICKET=jsonObject.getString("ticket");
Contants.ticket_expires_in=jsonObject.getInt("expires_in");
}
在步骤1和2已经为签名准备好了jsapi_ticket,再来看看JS-SDK使用的步骤三:通过config接口注入权限验证配置,在这个步骤,需要几个参数是要和服务器保持一致的:
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳(由开发者生成)
nonceStr: '', // 必填,生成签名的随机串 (由开发者生成)
signature: '',// 必填,签名 *(接下来计算这一个值是关键步骤)
jsApiList: [] // 必填,需要使用的JS接口列表
});
以下是生成JS-SDK配置文件所需要的参数的步骤和代码:
步骤1. 对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
public WxParam getEncryptJsapiTicket(@Context HttpServletRequest req , @Context HttpServletResponse resp, @RequestParam("url") String url) throws UnsupportedEncodingException {
String ticket=Contants.JSAPI_TICKET;
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//随机生成的时间戳
String noncestr = CommonUtil.getRandomString(16);//生成的16位随机码
String url1=java.net.URLDecoder.decode(url.split("=")[1],"UTF-8");//在调用js的页面完整URL
String signature=getSignature(url1, timestamp, noncestr);//开始进行sha1签名
WxParam wxparam=new WxParam();
wxparam.setNonce(noncestr);
wxparam.setSignature(signature);
wxparam.setTimestamp(timestamp);
return wxparam;
}
步骤2. 对string1进行sha1签名,得到signature:
public static String getSignature(String url,String timeStamp,String nonceStr){
//所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
String signValue = "jsapi_ticket="+Contants.JSAPI_TICKET+"&noncestr="+nonceStr+"×tamp="+timeStamp+"&url="+url;
String signature =DigestUtils.sha1Hex(signValue);
return signature;
}
到这里,生成页面需要的参数步骤已经完成了,这个时候需要在页面初始化的时候调用这个方法,获取相关参数,填充到we.config中即可调用成功。如果在开发过程中遇到报错,可以看微信的api附录,每一个报错信息都有对应的说明:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
接下来是时候贴一下页面的代码啦!
<script type="text/javascript">
var basePath= "<%=basePath%>";
var nonce="";//生成签名的随机串
var signature="";//签名
var timestamp="";//时间戳
var title="恭喜你!中奖啦!快戳我查看吧!";
var desc="原来中奖的感觉是那么美好!";
var sharLink="http://7ef60179.ngrok.io/wxh5/interestbills/index.jsp";
var imgUrl="http://7ef60179.ngrok.io/wxh5/interestbills/images/test.jpg";
$(document).ready(function(){
var url = encodeURI(location.href.split('#')[0]);
console.log("url=="+url);
$.ajax({
url: "./rest/wx/sdk/getEncryptJsapiTicket",
type: "POST",
data:{"url":url},
dataType: "json",
success: function(data){
console.log(data);
nonce=data.nonce;
signature=data.signature;
timestamp=data.timestamp;
loadWx();
},
error:function(err){
console.log('异常');
}
});
});
function loadWx(){
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: 'wx733b07f00930f0df', // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: nonce, // 必填,生成签名的随机串
signature: signature,// 必填,签名
jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表
});
wx.ready(function(){
//分享到朋友圈
wx.onMenuShareTimeline({
title: title, // 分享标题
link: sharLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: imgUrl, // 分享图标
success: function () {
alert("分享成功");
// 用户确认分享后执行的回调函数
},
cancel: function () {
alert("分享失败");
// 用户取消分享后执行的回调函数
}
});
//分享到朋友
wx.onMenuShareAppMessage({
title: title, // 分享标题
desc: desc, // 分享描述
link: sharLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: imgUrl, // 分享图标
type: 'link', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
alert("分享成功");
// 用户确认分享后执行的回调函数
},
cancel: function () {
alert("分享失败");
// 用户取消分享后执行的回调函数
}
});
//分享到QQ
wx.onMenuShareQQ({
title: title, // 分享标题
desc: desc, // 分享描述
link: sharLink, // 分享链接
imgUrl: imgUrl, // 分享图标
success: function () {
alert("分享成功");
// 用户确认分享后执行的回调函数
},
cancel: function () {
alert("分享失败");
// 用户取消分享后执行的回调函数
}
});
//分享到腾讯微博
wx.onMenuShareWeibo({
title: title, // 分享标题
desc: desc, // 分享描述
link: sharLink, // 分享链接
imgUrl: imgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
//分享到QQ空间
wx.onMenuShareQZone({
title: titlec, // 分享标题
desc: desc, // 分享描述
link: sharLink, // 分享链接
imgUrl: imgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
});
wx.error(function(res){
alert("验证失败了");
});
}
</script>
看看我的分享效果: