@(I-前端學(xué)習(xí))
網(wǎng)頁分享到微信中自定義標(biāo)題,內(nèi)容和圖片
隨便說說:
網(wǎng)頁現(xiàn)在也可以通過微信中直接打開,這就是用到時微信的瀏覽器,也可以通過微信瀏覽器中右上角進(jìn)行分享到朋友,朋友圈,QQ等。這是需要微信的JSSDK的機(jī)制所以還是要進(jìn)行一些配置才可以,而這些配置是需要微信公眾號的appId和appsecret的,所以如果沒有這些,也是不能進(jìn)行自定義的。
實(shí)現(xiàn)過程
- 首先可以先閱讀以下微信的JS-SDK的說明文檔
微信JS-SDK說明文檔 - 綁定域名,登錄微信公眾平臺,進(jìn)入“公眾號設(shè)置”的功能設(shè)置里面填寫js接口安全域名,這個是要填寫的是你微信瀏覽器要打開的域名地址。不能添加IP地址。
- 引入js文件
- 在需要調(diào)用js接口的頁面接入JS文件 http://res.wx.qq.com/open/js/jweixin-1.2.0.js
- 通過config接口注入權(quán)限并驗(yàn)證配置
- 這一步算是整個步驟中最關(guān)鍵的一步,必須正確的配置信息才可以進(jìn)行調(diào)用JS-SDK。
wx.config({
debug: true, // 開啟調(diào)試模式,調(diào)用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數(shù),可以在pc端打開,參數(shù)信息會通過log打出,僅在pc端時才會打印。
appId: '', // 必填,公眾號的唯一標(biāo)識
timestamp: , // 必填,生成簽名的時間戳
nonceStr: '', // 必填,生成簽名的隨機(jī)串
signature: '',// 必填,簽名
jsApiList: [] // 必填,需要使用的JS接口列表
});
下面講如何獲取 timestamp, noceStr(記得這個駝峰結(jié)構(gòu)),singature
獲取配置
先說說最煩人的singature,對于初學(xué)小程序的簡直要了老夫的命,這是啥玩意,還是簽名,所以我會把自己踩的坑給大家說一下。
獲取簽名實(shí)際是需要四步
1. 根據(jù)appId和appsecret獲取access_token;
2. 使用access_token獲取jsapi_ticket;
3. 使用時間戳,隨機(jī)數(shù),jsapi_ticket和要訪問的url按照簽名算法拼接字符串;
4. 對第三步的字符串進(jìn)行SHA1加密,得到簽名;
第一步,獲取access_token
appId和appsecret可以在微信公眾平臺--開發(fā)-基本配置中查找
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 設(shè)定文件
* @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鏈接和參數(shù)不能變
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;
}
這里拿到對應(yīng)的jsapi_ticket之后就可以進(jìn)行參數(shù)排序和拼接字符串并加密
第三步: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();
// 字節(jié)數(shù)組轉(zhuǎn)換為 十六進(jìn)制 數(shù)
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 "";
}
加密算法轉(zhuǎn)載自: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、時間戳和隨機(jī)字符串
String noncestr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);//隨機(jī)字符串
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//時間戳
System.out.println("accessToken:"+accessToken+"\njsapi_ticket:"+jsapi_ticket+"\n時間戳:"+timestamp+"\n隨機(jī)字符串:"+noncestr);
//4、獲取url
String url="http://www.luiyang.com/add.html";
/*根據(jù)JSSDK上面的規(guī)則進(jìn)行計(jì)算,這里比較簡單,我就手動寫啦
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、將參數(shù)排序并拼接字符串
String str = "jsapi_ticket="+jsapi_ticket+"&noncestr="+noncestr+"×tamp="+timestamp+"&url="+url;
//6、將字符串進(jìn)行sha1加密
String signature =SHA1(str);
System.out.println("參數(shù):"+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");
//轉(zhuǎn)換url
String url="";
//需要轉(zhuǎn)換解碼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、時間戳和隨機(jī)字符串
String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);//隨機(jī)字符串
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//時間戳
System.out.println("accessToken:"+aeecss_token+"\njsapi_ticket:"+aeecss_ticket+"\n時間戳:"+timestamp+"\n隨機(jī)字符串:"+nonceStr);
//4、獲取url
//5、將參數(shù)排序并拼接字符串
String str = "jsapi_ticket="+aeecss_ticket+"&noncestr="+nonceStr+"×tamp="+timestamp+"&url="+url;
//6、將字符串進(jìn)行sha1加密
String signature =SHA1(str);
System.out.println("參數(shù):"+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了,此時應(yīng)該是:
$.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, //調(diào)試階段建議開啟
appId: res.appId,//APPID
timestamp: res.timestamp,//上面main方法中拿到的時間戳timestamp
nonceStr: res.nonceStr,//上面main方法中拿到的隨機(jī)數(shù)nonceStr
signature: res.signature,//上面main方法中拿到的簽名signature
//需要調(diào)用的方法接口
jsApiList: [ 'onMenuShareTimeline','onMenuShareAppMessage','onMenuShareWeibo','onMenuShareQQ','onMenuShareQZone']
});
}
注意:
- url一定要是完整的url(當(dāng)前網(wǎng)頁的URL,不包含#及其后面部分)最好是使用window.location.href.split("#")獲取得到,如果傳入固定的好像會報invalid signature錯誤,所以為了安全起見還是直接傳入當(dāng)前的url
- 這個簽名的有效時間為7200秒,也就是2個小時,因此當(dāng)超過兩個小時候,再訪問也會報invalid signature錯誤。但是這個我還沒有遇見,并不知道這么解決,其他說是需要緩存access_token和access_ticket
- 另外還有一個錯誤:invalid url domain
這個跟生成簽名時用的url有關(guān)系,官網(wǎng)的說法是:
invalid url domain當(dāng)前頁面所在域名與使用的appid沒有綁定,請確認(rèn)正確填寫綁定的域名,如果使用了端口號,則配置的綁定域名也要加上端口號(一個appid可以綁定三個有效域名)
這個url必須是:“公眾號設(shè)置---功能設(shè)置----JS接口安全域名”中綁定的三個域名之一 - 如果以上配置都是正確,而且debug也設(shè)置為true了,在微信中訪問連接會出現(xiàn)config:ok的界面,就說明配置成功了
- 有時也可以把a(bǔ)jax請求放在setTimeout中進(jìn)行請求。
自定義標(biāo)題,內(nèi)容和圖片
wx.ready(function(){
// alert("我已經(jīng)進(jìn)來了");
wx.onMenuShareTimeline({
title: title, // 分享標(biāo)題
link: window.location.href, // 分享鏈接,該鏈接域名或路徑必須與當(dāng)前頁面對應(yīng)的公眾號JS安全域名一致
imgUrl: "http://upload-images.jianshu.io/upload_images/3429385-09282d70c0390d94.png?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240", // 分享圖標(biāo)
success: function () {
// alert("成功")
// 用戶點(diǎn)擊了分享后執(zhí)行的回調(diào)函數(shù)
}
});
wx.onMenuShareAppMessage({
title: title, // 分享標(biāo)題
desc: descContent, // 分享描述
link: window.location.href, // 分享鏈接,該鏈接域名或路徑必須與當(dāng)前頁面對應(yīng)的公眾號JS安全域名一致
imgUrl: "http://upload-images.jianshu.io/upload_images/3429385-09282d70c0390d94.png?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240", // 分享圖標(biāo)
type: '', // 分享類型,music、video或link,不填默認(rèn)為link
dataUrl: '', // 如果type是music或video,則要提供數(shù)據(jù)鏈接,默認(rèn)為空
success: function () {
// alert("成功")
// 用戶點(diǎn)擊了分享后執(zhí)行的回調(diào)函數(shù)
}
});
wx.onMenuShareQQ({
title: title, // 分享標(biāo)題
desc: descContent, // 分享描述
link: window.location.href, // 分享鏈接
imgUrl: "http://upload-images.jianshu.io/upload_images/3429385-09282d70c0390d94.png?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240", // 分享圖標(biāo)
success: function () {
// alert("成功")
// 用戶確認(rèn)分享后執(zhí)行的回調(diào)函數(shù)
},
cancel: function () {
// alert("失敗")
// 用戶取消分享后執(zhí)行的回調(diào)函數(shù)
// config信息驗(yàn)證失敗會執(zhí)行error函數(shù),如簽名過期導(dǎo)致驗(yàn)證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數(shù)中查看,對于SPA可以在這里更新簽名。
}
});
});
注意:
- 應(yīng)該把自定義的內(nèi)容卸載wx.ready(
// config信息驗(yàn)證后會執(zhí)行ready方法,所有接口調(diào)用都必須在config接口獲得結(jié)果之后,config是一個客戶端的異步操作,所以如果需要在頁面加載時就調(diào)用相關(guān)接口,則須把相關(guān)接口放在ready函數(shù)中調(diào)用來確保正確執(zhí)行。對于用戶觸發(fā)時才調(diào)用的接口,則可以直接調(diào)用,不需要放在ready函數(shù)中。
)里面, - link該鏈接域名或路徑必須與當(dāng)前頁面對應(yīng)的公眾號JS安全域名
- imgUrl:最好是絕對地址的圖片,相對位置好像出不來 比如:'../assets/image/213.png'這樣是出不來的
驗(yàn)證工具:
微信公眾平臺接口調(diào)試工具
微信 JS 接口簽名校驗(yàn)工具
參考:
解決微信JS-SDK掃一掃功能接入以及出現(xiàn)簽名無效 invalid signature
微信JS-SDK獲取signature簽名以及config配置