@(I-前端学习)
网页分享到微信中自定义标题,内容和图片
随便说说:
网页现在也可以通过微信中直接打开,这就是用到时微信的浏览器,也可以通过微信浏览器中右上角进行分享到朋友,朋友圈,QQ等。这是需要微信的JSSDK的机制所以还是要进行一些配置才可以,而这些配置是需要微信公众号的appId和appsecret的,所以如果没有这些,也是不能进行自定义的。
实现过程
- 首先可以先阅读以下微信的JS-SDK的说明文档
微信JS-SDK说明文档 - 绑定域名,登录微信公众平台,进入“公众号设置”的功能设置里面填写js接口安全域名,这个是要填写的是你微信浏览器要打开的域名地址。不能添加IP地址。
- 引入js文件
- 在需要调用js接口的页面接入JS文件 http://res.wx.qq.com/open/js/jweixin-1.2.0.js
- 通过config接口注入权限并验证配置
- 这一步算是整个步骤中最关键的一步,必须正确的配置信息才可以进行调用JS-SDK。
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
下面讲如何获取 timestamp, noceStr(记得这个驼峰结构),singature
获取配置
先说说最烦人的singature,对于初学小程序的简直要了老夫的命,这是啥玩意,还是签名,所以我会把自己踩的坑给大家说一下。
获取签名实际是需要四步
1. 根据appId和appsecret获取access_token;
2. 使用access_token获取jsapi_ticket;
3. 使用时间戳,随机数,jsapi_ticket和要访问的url按照签名算法拼接字符串;
4. 对第三步的字符串进行SHA1加密,得到签名;
第一步,获取access_token
appId和appsecret可以在微信公众平台--开发-基本配置中查找
public static String getAccess_token(String appId, String appSecret){
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
String accessToken = null;
try
{
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String message = new String(jsonBytes, "UTF-8");
JSONObject jsonObj = JSONObject.fromObject(message);
accessToken = jsonObj.getString("access_token");
}
catch (Exception e)
{
e.printStackTrace();
}
return accessToken;
}
第二步 获取jsapi_ticket
/**
* 获得ACCESS_TICKET
*
* @Title: ACCESS_TICKET
* @Description: 获得ACCESS_TICKET
* @param @return 设定文件
* @return String 返回类型
* @throws
*/
public static String getAccess_ticket(String access_token) {
String ticket = null;
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ access_token +"&type=jsapi";//这个url链接和参数不能变
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String message = new String(jsonBytes, "UTF-8");
JSONObject demoJson = JSONObject.fromObject(message);
System.out.println("JSON字符串:"+demoJson);
ticket = demoJson.getString("ticket");
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return ticket;
}
这里拿到对应的jsapi_ticket之后就可以进行参数排序和拼接字符串并加密
第三步:SHA1加密
public static String SHA1(String decript) {
try {
MessageDigest digest = java.security.MessageDigest.getInstance("SHA-1");
digest.update(decript.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
加密算法转载自:http://www.open-open.com/lib/view/open1392185662160.html
第四步: 获取签名
public static void main(String[] args) {
//1、获取AccessToken
String accessToken = getAccessToken();
//2、获取Ticket
String jsapi_ticket = getTicket(accessToken);
//3、时间戳和随机字符串
String noncestr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);//随机字符串
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳
System.out.println("accessToken:"+accessToken+"\njsapi_ticket:"+jsapi_ticket+"\n时间戳:"+timestamp+"\n随机字符串:"+noncestr);
//4、获取url
String url="http://www.luiyang.com/add.html";
/*根据JSSDK上面的规则进行计算,这里比较简单,我就手动写啦
String[] ArrTmp = {"jsapi_ticket","timestamp","nonce","url"};
Arrays.sort(ArrTmp);
StringBuffer sf = new StringBuffer();
for(int i=0;i<ArrTmp.length;i++){
sf.append(ArrTmp[i]);
}
*/
//5、将参数排序并拼接字符串
String str = "jsapi_ticket="+jsapi_ticket+"&noncestr="+noncestr+"×tamp="+timestamp+"&url="+url;
//6、将字符串进行sha1加密
String signature =SHA1(str);
System.out.println("参数:"+str+"\n签名:"+signature);
}
改写之后的代码,json格式返回。
protected void doPost(HttpServletRequest request, HttpServletResponse response){
//appId和appSecret
String appId = "XXXXX";
String appSecret = "XXXXX";
//外部传入url获取url url需要是微信中打开的url否则会报错。
String URL = request.getParameter("url");
//转换url
String url="";
//需要转换解码url
try {
url = java.net.URLDecoder.decode(URL,"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//获取access_token
String aeecss_token = HttpUtil.getAccess_token(appId, appSecret);
//获取access_ticket
String aeecss_ticket = HttpUtil.getAccess_ticket(aeecss_token);
//3、时间戳和随机字符串
String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);//随机字符串
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳
System.out.println("accessToken:"+aeecss_token+"\njsapi_ticket:"+aeecss_ticket+"\n时间戳:"+timestamp+"\n随机字符串:"+nonceStr);
//4、获取url
//5、将参数排序并拼接字符串
String str = "jsapi_ticket="+aeecss_ticket+"&noncestr="+nonceStr+"×tamp="+timestamp+"&url="+url;
//6、将字符串进行sha1加密
String signature =SHA1(str);
System.out.println("参数:"+str+"\n签名:"+signature);
Map<String,String> map=new HashMap();
map.put("appId",appId);
map.put("timestamp",timestamp);
map.put("accessToken",aeecss_token);
map.put("ticket",aeecss_ticket);
map.put("nonceStr",nonceStr);
map.put("signature",signature);
JSONObject jsonObject = JSONObject.fromObject(map);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setContentType("application/json;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter pw = null;
try {
pw = response.getWriter();
} catch (IOException e1) {
logger.error("**********reponse getWriter exception**********");
e1.printStackTrace();
}
pw.write(jsonObject.toString());
pw.close();
}
这一段代码是改写了,获取签名后把所有的信息都返回json格式了。概要的都有了,这是就可以配置config了,此时应该是:
$.ajax({
url: 'http://10.25.74.68:8088',
type: 'POST',
dataType: 'json',
//url需要编码传入而且要是完整的url除#之后的
data: {"url":encodeURIComponent(window.location.href.split("#")[0])}
})
.done(function(res) {
wx.config({
debug: ture, //调试阶段建议开启
appId: res.appId,//APPID
timestamp: res.timestamp,//上面main方法中拿到的时间戳timestamp
nonceStr: res.nonceStr,//上面main方法中拿到的随机数nonceStr
signature: res.signature,//上面main方法中拿到的签名signature
//需要调用的方法接口
jsApiList: [ 'onMenuShareTimeline','onMenuShareAppMessage','onMenuShareWeibo','onMenuShareQQ','onMenuShareQZone']
});
}
注意:
- url一定要是完整的url(当前网页的URL,不包含#及其后面部分)最好是使用window.location.href.split("#")获取得到,如果传入固定的好像会报invalid signature错误,所以为了安全起见还是直接传入当前的url
- 这个签名的有效时间为7200秒,也就是2个小时,因此当超过两个小时候,再访问也会报invalid signature错误。但是这个我还没有遇见,并不知道这么解决,其他说是需要缓存access_token和access_ticket
- 另外还有一个错误:invalid url domain
这个跟生成签名时用的url有关系,官网的说法是:
invalid url domain当前页面所在域名与使用的appid没有绑定,请确认正确填写绑定的域名,如果使用了端口号,则配置的绑定域名也要加上端口号(一个appid可以绑定三个有效域名)
这个url必须是:“公众号设置---功能设置----JS接口安全域名”中绑定的三个域名之一 - 如果以上配置都是正确,而且debug也设置为true了,在微信中访问连接会出现config:ok的界面,就说明配置成功了
- 有时也可以把ajax请求放在setTimeout中进行请求。
自定义标题,内容和图片
wx.ready(function(){
// alert("我已经进来了");
wx.onMenuShareTimeline({
title: title, // 分享标题
link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: "//upload-images.jianshu.io/upload_images/3429385-09282d70c0390d94.png?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240", // 分享图标
success: function () {
// alert("成功")
// 用户点击了分享后执行的回调函数
}
});
wx.onMenuShareAppMessage({
title: title, // 分享标题
desc: descContent, // 分享描述
link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: "//upload-images.jianshu.io/upload_images/3429385-09282d70c0390d94.png?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240", // 分享图标
type: '', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
// alert("成功")
// 用户点击了分享后执行的回调函数
}
});
wx.onMenuShareQQ({
title: title, // 分享标题
desc: descContent, // 分享描述
link: window.location.href, // 分享链接
imgUrl: "//upload-images.jianshu.io/upload_images/3429385-09282d70c0390d94.png?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240", // 分享图标
success: function () {
// alert("成功")
// 用户确认分享后执行的回调函数
},
cancel: function () {
// alert("失败")
// 用户取消分享后执行的回调函数
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
}
});
});
注意:
- 应该把自定义的内容卸载wx.ready(
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
)里面, - link该链接域名或路径必须与当前页面对应的公众号JS安全域名
- imgUrl:最好是绝对地址的图片,相对位置好像出不来 比如:'../assets/image/213.png'这样是出不来的
验证工具:
微信公众平台接口调试工具
微信 JS 接口签名校验工具
参考:
解决微信JS-SDK扫一扫功能接入以及出现签名无效 invalid signature
微信JS-SDK获取signature签名以及config配置