javascript
手把手带你使用JS-SDK自定义微信分享效果
前言
剛進入一家新公司,接到的第一個任務就是需要需要自定義微信分享的效果(自定義縮略圖,標題,摘要),一開始真是一臉懵逼,在網上搜索了半天之后大概有了方案。值得注意的是一開始搜索到的解決方案全是調用微信的自帶的JS-SDK,然而騰訊是不會讓廣大吃瓜群眾這么輕而易舉的調用他們的東西的。微信開發團隊已經把調用的權限收回,現在無法直接在頁面直接調用JS-SDK了。話不多說,直接上干貨。
預期效果
原始的分享效果:
?
使用微信JS-SDK的分享效果:
可以看出縮略圖,標題,摘要樣式良好,給用戶的體驗很好。
準備工作
微信官方開發者文檔地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
現在的思路已經很明確了,就是通過調用微信的JS-SDK實現自定義分享效果。但是這個調用過程比較繁瑣,需要提前準備如下東西:
(1)微信服務號一個,并且已經通過了實名認證;
沒有實名認證的話,一些接口沒有調用權限。
(2)一個ICP備案的域名;
這個域名需要設置為微信公眾號后臺的JS接口安全域名,否則微信仍然不允許調用它的接口。
這時大家應該就犯難了,這樣的話豈不是不能在本地測試,只能部署到生產環境才能測試?不用著急,解決方案告訴大家:花生殼的內網穿透服務(收費,20元以內)
花生殼官網:http://hsk.oray.com/price/#personal
選擇個人免費版就可以了,雖然說是免費版,但是其實注冊過程中還是要收幾塊錢的,因為我自己買了域名和流量所以花的錢更多一些,但也在20元以內。不建議大家購買流量,送的流量可以用很久了。
當準備好上面提到的就可以開始敲代碼了。
(3)安裝微信開發者工具,用于本地調試。
下載地址:https://mp.weixin.qq.com/debug/cgi-bin/webdebugger/download?from=mpwiki&os=x64
官方使用教程:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140
具體步驟
(1)查看AppId,AppSecret以及綁定域名
進入微信后臺,找到下面的菜單
獲取AppID和AppSecret
設置JS接口安全域名
?
?
注意第三步,如果微信服務器不能在我們的服務器上訪問到這個txt文件,域名是無法設置成功的,這里先告訴大家在哪里設置,想要成功設置域名還需要使用花生殼的服務,讓微信服務器訪問我們本地工程中的的txt文件才行。
hkh3321313.vicp.io是在花生殼上購買的域名,免費送的域名是在太難記了,完全不能忍。
?
(2)引入JS文件
這里需要注意是http還是https,如果生產環境是https,務必前綴是https,都則會出現mix content這樣的錯誤,導致引入失敗。
<script typet="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>?
(3)通過AppId和AppSecret請求accessToken,然后通過accessToken獲取jsapi_ticket,生成config接口所需參數
因為獲取這兩個參數的次數是有限制的(accessToke 每日2000次,jsapi_ticket 每日100000次),有效期是7200秒,每兩小時請求一次就行啦,把獲取的accessToke和jsapi_ticket保存在后臺,所以accessToken和jsapi_ticket這兩個參數的獲取是通過ajax方式請求后臺,而不是實時去獲取的。
config幾個參數需要詳細說明一下:
附上signature算法的官方說明:
https://mp.weixin.qq.com/wiki?action=doc&id=mp1421141115&t=0.15697429783636763#buzhou3
在附錄1中可以找到詳細說明。
此外,官方提供了一個簽名算法的校驗工具:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
下面只附上了主要的方法:
//獲取accessToken private JSONObject getAccessToken(){//String accessTokenUrl= https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRETString requestUrl = accessTokenUrl.replace("APPID",appId).replace("APPSECRET",appSecret);log.info("getAccessToken.requestUrl====>"+requestUrl);JSONObject result = HttpUtil.doGet(requestUrl);return result ; }//獲取ticket private JSONObject getJsApiTicket(){//String apiTicketUrl= https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapiString requestUrl = apiTicketUrl.replace("ACCESS_TOKEN", accessToken);log.info("getJsApiTicket.requestUrl====>"+requestUrl);JSONObject result = HttpUtil.doGet(requestUrl);return result; }//生成微信權限驗證的參數 public Map<String, String> makeWXTicket(String jsApiTicket, String url) {Map<String, String> ret = new HashMap<String, String>();String nonceStr = createNonceStr();String timestamp = createTimestamp();String string1;String signature = "";//注意這里參數名必須全部小寫,且必須有序string1 = "jsapi_ticket=" + jsApiTicket +"&noncestr=" + nonceStr +"×tamp=" + timestamp +"&url=" + url;log.info("String1=====>"+string1);try{MessageDigest crypt = MessageDigest.getInstance("SHA-1");crypt.reset();crypt.update(string1.getBytes("UTF-8"));signature = byteToHex(crypt.digest());log.info("signature=====>"+signature);}catch (NoSuchAlgorithmException e){log.error("WeChatController.makeWXTicket=====Start");log.error(e.getMessage(),e);log.error("WeChatController.makeWXTicket=====End");}catch (UnsupportedEncodingException e){log.error("WeChatController.makeWXTicket=====Start");log.error(e.getMessage(),e);log.error("WeChatController.makeWXTicket=====End");}ret.put("url", url);ret.put("jsapi_ticket", jsApiTicket);ret.put("nonceStr", nonceStr);ret.put("timestamp", timestamp);ret.put("signature", signature);ret.put("appid", appId);return ret; } //字節數組轉換為十六進制字符串 private static String byteToHex(final byte[] hash) {Formatter formatter = new Formatter();for (byte b : hash){formatter.format("%02x", b);}String result = formatter.toString();formatter.close();return result; } //生成隨機字符串 private static String createNonceStr() {return UUID.randomUUID().toString(); } //生成時間戳 private static String createTimestamp() {return Long.toString(System.currentTimeMillis() / 1000); }HttpUtil代碼
public class HttpUtil {public static Log logger = LogFactory.getLog(HttpUtil.class);//get請求 public static com.alibaba.fastjson.JSONObject doGet(String requestUrl) {CloseableHttpClient httpClient = HttpClients.createDefault();CloseableHttpResponse response = null;String responseContent = null;com.alibaba.fastjson.JSONObject result = null;try {//創建Get請求,HttpGet httpGet = new HttpGet(requestUrl);//執行Get請求,response = httpClient.execute(httpGet);//得到響應體HttpEntity entity = response.getEntity();//獲取響應內容responseContent = EntityUtils.toString(entity,"UTF-8");//轉換為mapresult = JSON.parseObject(responseContent);} catch (IOException e) {logger.error("HttpUtil=====Start");logger.error(e.getMessage(),e);logger.error("HttpUtil=====End");}return result;} }?
(4)通過config接口注入權限驗證配置
官方示例:
wx.config({ debug: true, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。appId: '', // 必填,公眾號的唯一標識timestamp: , // 必填,生成簽名的時間戳nonceStr: '', // 必填,生成簽名的隨機串
signature: '',// 必填,簽名,見附錄1jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2 });
自己的代碼:
其中的url不能硬編碼寫在后臺,必須通過動態傳遞。
$(function(){var url = location.href.split('#').toString();//url不能寫死 $.ajax({type : "get",url : "/wechatParam",dataType : "json",async : false,data:{url:url},success : function(data) {wx.config({debug: false,////生產環境需要關閉debug模式appId: data.appid,//appId通過微信服務號后臺查看timestamp: data.timestamp,//生成簽名的時間戳nonceStr: data.nonceStr,//生成簽名的隨機字符串signature: data.signature,//簽名jsApiList: [//需要調用的JS接口列表'checkJsApi',//判斷當前客戶端版本是否支持指定JS接口'onMenuShareTimeline',//分享給好友'onMenuShareAppMessage'//分享到朋友圈 ]});},error: function(xhr, status, error) {//alert(status);//alert(xhr.responseText); }}) });?
(5)通過ready接口處理成功驗證
官方示例:
wx.ready(function(){// config信息驗證后會執行ready方法,所有接口調用都必須在config接口獲得結果之后,config是一個客戶端的異步操作,所以如果需要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對于用戶觸發時才調用的接口,則可以直接調用,不需要放在ready函數中。 });自己的代碼:
wx.ready(function () {var link = window.location.href;var protocol = window.location.protocol;var host = window.location.host;//分享朋友圈 wx.onMenuShareTimeline({title: '這是一個自定義的標題!',link: link,imgUrl: protocol+'//'+host+'/resources/images/icon.jpg',// 自定義圖標trigger: function (res) {// 不要嘗試在trigger中使用ajax異步請求修改本次分享的內容,因為客戶端分享操作是一個同步操作,這時候使用ajax的回包會還沒有返回.//alert('click shared'); },success: function (res) {//alert('shared success');//some thing you should do },cancel: function (res) {//alert('shared cancle'); },fail: function (res) {//alert(JSON.stringify(res)); }});//分享給好友 wx.onMenuShareAppMessage({title: '這是一個自定義的標題!', // 分享標題desc: '這是一個自定義的描述!', // 分享描述link: link, // 分享鏈接,該鏈接域名或路徑必須與當前頁面對應的公眾號JS安全域名一致imgUrl: protocol+'//'+host+'/resources/images/icon.jpg', // 自定義圖標type: 'link', // 分享類型,music、video或link,不填默認為linkdataUrl: '', // 如果type是music或video,則要提供數據鏈接,默認為空success: function () {// 用戶確認分享后執行的回調函數 },cancel: function () {// 用戶取消分享后執行的回調函數 }});wx.error(function (res) {alert(res.errMsg);});});到這里所有的代碼都已經分享完畢了。
?
(6)啟動花生殼的內網穿透服務,設置JS接口安全域名
這個基本是傻瓜式的,只要下載他們的客戶端就可以了。
官網教程:http://hsk.oray.com/news/4345.html
添加一個映射就可以了
把之前下載的txt文件放在工程目錄webapp下,然后本地啟動工程,確定通過域名可以訪問本地項目后,設置JS安全域名
現在訪問 域名:端口號(例如:hkh3321313.vicp.io:8080)就可以訪問本地項目啦。
?
(7)使用微信開發者工具測試
微信開發者工具其實就是微信的瀏覽器,其中集成了chrome的調試工具,前面提到wx.config中的debug模式這里就發揮作用了,瀏覽器會自動彈出調用微信接口的返回結果。
成功返回的話結果應該是ok什么的,圖就不上了。提醒大家,上生產環境一定要把debug改為false~
?
后記
?雖然已經給了主要的代碼,大家一定還是不想寫接口,下面附上完整的代碼,如果你覺得解了燃眉之急,就點個頂吧,哈哈哈~
@Controller public class WeChatController {private final Logger log = LoggerFactory.getLogger(this.getClass());//獲取相關的參數,在application.properties文件中@Value("${wechat.appId}")private String appId;@Value("${wechat.appSecret}")private String appSecret;@Value("${wechat.url.accessToken}")private String accessTokenUrl;@Value("${wechat.url.apiTicket}")private String apiTicketUrl;//微信參數 private String accessToken;private String jsApiTicket;//獲取參數的時刻private Long getTiketTime = 0L;private Long getTokenTime = 0L;//參數的有效時間,單位是秒(s)private Long tokenExpireTime = 0L;private Long ticketExpireTime = 0L;//獲取微信參數@RequestMapping("/wechatParam")@ResponseBodypublic Map<String, String> getWechatParam(String url){//當前時間long now = System.currentTimeMillis();log.info("currentTime====>"+now+"ms");//判斷accessToken是否已經存在或者token是否過期if(StringUtils.isBlank(accessToken)||(now - getTokenTime > tokenExpireTime*1000)){JSONObject tokenInfo = getAccessToken();if(tokenInfo != null){log.info("tokenInfo====>"+tokenInfo.toJSONString());accessToken = tokenInfo.getString("access_token");tokenExpireTime = tokenInfo.getLongValue("expires_in");//獲取token的時間getTokenTime = System.currentTimeMillis();log.info("accessToken====>"+accessToken);log.info("tokenExpireTime====>"+tokenExpireTime+"s");log.info("getTokenTime====>"+getTokenTime+"ms");}else{log.info("====>tokenInfo is null~");log.info("====>failure of getting tokenInfo,please do some check~");}}//判斷jsApiTicket是否已經存在或者是否過期if(StringUtils.isBlank(jsApiTicket)||(now - getTiketTime > ticketExpireTime*1000)){JSONObject ticketInfo = getJsApiTicket();if(ticketInfo!=null){log.info("ticketInfo====>"+ticketInfo.toJSONString());jsApiTicket = ticketInfo.getString("ticket");ticketExpireTime = ticketInfo.getLongValue("expires_in");getTiketTime = System.currentTimeMillis();log.info("jsApiTicket====>"+jsApiTicket);log.info("ticketExpireTime====>"+ticketExpireTime+"s");log.info("getTiketTime====>"+getTiketTime+"ms");}else{log.info("====>ticketInfo is null~");log.info("====>failure of getting tokenInfo,please do some check~");}}//生成微信權限驗證的參數Map<String, String> wechatParam= makeWXTicket(jsApiTicket,url);return wechatParam;}//獲取accessToken private JSONObject getAccessToken(){//String accessTokenUrl = https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRETString requestUrl = accessTokenUrl.replace("APPID",appId).replace("APPSECRET",appSecret);log.info("getAccessToken.requestUrl====>"+requestUrl);JSONObject result = HttpUtil.doGet(requestUrl);return result ;}//獲取ticket private JSONObject getJsApiTicket(){//String apiTicketUrl = https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapiString requestUrl = apiTicketUrl.replace("ACCESS_TOKEN", accessToken);log.info("getJsApiTicket.requestUrl====>"+requestUrl);JSONObject result = HttpUtil.doGet(requestUrl);return result;}//生成微信權限驗證的參數public Map<String, String> makeWXTicket(String jsApiTicket, String url) {Map<String, String> ret = new HashMap<String, String>();String nonceStr = createNonceStr();String timestamp = createTimestamp();String string1;String signature = "";//注意這里參數名必須全部小寫,且必須有序string1 = "jsapi_ticket=" + jsApiTicket +"&noncestr=" + nonceStr +"×tamp=" + timestamp +"&url=" + url;log.info("String1=====>"+string1);try{MessageDigest crypt = MessageDigest.getInstance("SHA-1");crypt.reset();crypt.update(string1.getBytes("UTF-8"));signature = byteToHex(crypt.digest());log.info("signature=====>"+signature);}catch (NoSuchAlgorithmException e){log.error("WeChatController.makeWXTicket=====Start");log.error(e.getMessage(),e);log.error("WeChatController.makeWXTicket=====End");}catch (UnsupportedEncodingException e){log.error("WeChatController.makeWXTicket=====Start");log.error(e.getMessage(),e);log.error("WeChatController.makeWXTicket=====End");}ret.put("url", url);ret.put("jsapi_ticket", jsApiTicket);ret.put("nonceStr", nonceStr);ret.put("timestamp", timestamp);ret.put("signature", signature);ret.put("appid", appId);return ret;}//字節數組轉換為十六進制字符串private static String byteToHex(final byte[] hash) {Formatter formatter = new Formatter();for (byte b : hash){formatter.format("%02x", b);}String result = formatter.toString();formatter.close();return result;}//生成隨機字符串 private static String createNonceStr() {return UUID.randomUUID().toString();}//生成時間戳 private static String createTimestamp() {return Long.toString(System.currentTimeMillis() / 1000);} }?
轉載于:https://www.cnblogs.com/backtozero/p/7064247.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的手把手带你使用JS-SDK自定义微信分享效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实验四+149+肖雷
- 下一篇: 设计一个带有getmin功能的栈,保证时