最近做項目要用到微信分享功能,由於之前微信公眾號的功能沒怎么接觸過,所以相對陌生。
以至於到前台頁面調用jsapi時老是報各種錯誤,包括:invalid signature,updateAppMessageShareData Permission Denied這些錯誤。
故作此備忘:
官方開發文檔:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
A.需要公眾號開發信息中的 AppID,AppSecret。
1.獲取token,每次請求時生成的token有效期為7200秒,注意每天有限制該接口調用次數,所以要做好緩存。
后台使用接口https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $weixin['AppID'] . "&secret=" . $weixin['AppSecret']

1 //使用get 請求,從微信服務器獲取 token 2 $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $weixin['AppID'] . "&secret=" . $weixin['AppSecret']; 3 //返回的是json格式 4 $access_token = json_decode(curlGet($url),true); 5 6 if($access_token['access_token']==''||$access_token['access_token']==null){ 7 return array('success'=>0,'error'=>'獲取token的配置參數有誤'); 8 }else{ 9 //將token 傳入緩存中(保存時間為3600秒=一小時) 10 S('Wxzj_Access_Token',$access_token['access_token'],array('expire'=>3600*1.5)); 11 return array('success'=>$access_token['access_token']); 12 }
2.根據token獲取ticket

1 if($token=S('Wxzj_Access_Token')){ 2 $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$token}&type=jsapi"; 3 $res = curlGet($url); 4 $res = json_decode($res, true); 5 if($res['errcode']!=0) { 6 return null; 7 } else { 8 S('Wxzj_jssdk_ticket', $res['ticket'], 3600); 9 } 10 return S('Wxzj_jssdk_ticket'); 11 }else{ 12 return null; 13 }
3.前台通過ajax傳遞url(處理過的url)到后台方法,通過方法拼裝簽名后,再返回結果。需要注意的是url所在域名必須添加在 微信公眾平台-》公眾號設置-》功能設置-》JS接口安全域名。且 微信公眾平台-》開發-》基本配置-》IP白名單 需要添加url所在域名的ip地址
a).前台js代碼

1 <script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script> 2 3 <script> 4 /* 5 * url 目標url 6 * arg 需要替換的參數名稱 7 * arg_val 替換后的參數的值 8 * return url 參數替換后的url 9 */ 10 function changeURLArg(url,arg,arg_val){ 11 var pattern=arg+'=([^&]*)'; 12 var replaceText=arg+'='+arg_val; 13 if(url.match(pattern)){ 14 var tmp='/('+ arg+'=)([^&]*)/gi'; 15 tmp=url.replace(eval(tmp),replaceText); 16 return tmp; 17 }else{ 18 if(url.match('[\?]')){ 19 return url+'&'+replaceText; 20 }else{ 21 return url+'?'+replaceText; 22 } 23 } 24 } 25 26 /** 27 * 獲取url參數值 28 * @param name 參數名 29 * @returns 30 * @author Donlyn 31 * <li>created at 2018-02-12</li> 32 */ 33 function GetQueryString(name) { 34 var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)","i"); 35 var r = window.location.search.substr(1).match(reg); 36 if (r!=null) return unescape(r[2]); return null; 37 } 38 39 var url = ''; 40 // 通過后台生成簽名,因為之前都是直接在微信打開頁面加載時就直接獲取簽名,導致老是報invalid signature的錯誤,后來查文檔才發現這樣不行。 41 //附錄5-常見錯誤及解決方法 11.invalid signature簽名失敗(后台生成簽名的鏈接為使用jssdk的當前鏈接,也就是跳轉后的b鏈接,請不要用微信登錄的授權鏈接進行簽名計算,后台簽名的url一定是使用jssdk的當前頁面的完整url除去'#'部分) 42 $.ajax({ 43 url : 'initJsapi', 44 type : 'post', 45 data : {url:(window.location.href).split('#')[0]}, 46 success :function(res){ 47 //alert(res); 48 var params = JSON.parse(res); 49 url = params.url; 50 51 // =============這里我重新拼裝了url,以修改要分享出去的鏈接============ 52 var share_mid = $('#MemberID').val(); 53 if(share_mid!=0){ 54 var id_val = GetQueryString('id'); 55 var url_params_id_tmp = id_val.split('.'); 56 if(url_params_id_tmp.length==2 || (url_params_id_tmp.length>2 && (url_params_id_tmp[2]==0))){ 57 id_val += '.'+share_mid; 58 url = changeURLArg(url,'id', id_val); 59 }else if(url_params_id_tmp.length>2 && url_params_id_tmp[2]!=share_mid){ 60 url_params_id_tmp[2] = share_mid; 61 id_val = url_params_id_tmp.join("."); 62 url = changeURLArg(url, 'id', id_val); 63 } 64 } 65 //=========修改url到這里結束========== 66 67 /*配置 wx.config 參數*/ 68 wx.config({ 69 debug: false, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。 70 appId: params.appId, // 必填,企業號的唯一標識,此處填寫企業號corpid 71 timestamp: params.timestamp, // 必填,生成簽名的時間戳 72 nonceStr: params.nonceStr, // 必填,生成簽名的隨機串 73 signature: params.signature,// 必填,簽名,見附錄1 74 jsApiList: [ 75 'checkJsApi', 76 'updateAppMessageShareData', 77 'hideMenuItems', 78 'onMenuShareAppMessage' 79 ] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2 80 }); 81 } 82 }); 83 wx.ready(function(){ 84 85 // 這里禁用掉右上角菜單中的一些按鈕 86 wx.hideMenuItems({ 87 menuList: [ 88 "menuItem:share:qq", 89 "menuItem:share:weiboApp", 90 "menuItem:share:facebook", 91 "menuItem:share:timeline", 92 "menuItem:share:QZone", 93 94 "menuItem:editTag", 95 "menuItem:delete", 96 //"menuItem:copyUrl", 97 "menuItem:originPage", 98 "menuItem:readMode", 99 "menuItem:openWithQQBrowser", 100 "menuItem:openWithSafari", 101 "menuItem:share:email", 102 ] // 要隱藏的菜單項,只能隱藏“傳播類”和“保護類”按鈕,所有menu項見附錄3 103 }); 104 wx.error(function(res) { 105 alert(JSON.stringify(res)); 106 }); 107 wx.checkJsApi({ 108 jsApiList: ['updateAppMessageShareData','onMenuShareAppMessage'/* 'onMenuShareAppMessage' */], // 需要檢測的JS接口列表,所有JS接口列表見附錄2, 109 success: function(res) { 110 // 以鍵值對的形式返回,可用的api值true,不可用為false 111 // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"} 112 //alert(JSON.stringify(res)); 113 } 114 }); 115 // 這個接口是舊版本接口,分享給好友,此接口即將失效,但是因為要用到判斷“是否分享成功”,所以暫時使用着。1.4.0版本接口為updateAppMessageShareData,不能判斷是否分享成功 116 wx.onMenuShareAppMessage({ 117 "imgUrl" : "imgUrl", // 分享顯示的縮略圖地址 118 "link" : url, // 分享地址 119 "desc" : "desc", // 分享描述 120 "title" : "Title", // 分享標題 121 success : function(){ 122 // 分享成功可以做相應的數據處理 123 /* alert("分享成功"); 124 return; */ 125 126 } 127 }); 128 //wx.onMenuShareAppMessage(shareData); 129 }); 130 </script>
b).后台php,通過前台傳遞過來的url參數進行簽名,並返回。這里要注意拼接簽名字符串 $str 的參數的先后順序

1 function initJsapi(){ 2 if(IS_POST) { 3 $url = $_POST['url']; 4 $res = array(); 5 // ======================== Start at 2017/05/27 1015 ======================== // 6 $jsapi_ticket = S('Wxzj_jssdk_ticket'); 7 if($jsapi_ticket){ 8 $noncestr = rand_string(16);//16位長度隨機字符串 9 $timestamp = time(); 10 // 拼接簽名字符串 11 $str = 'jsapi_ticket='.$jsapi_ticket.'&noncestr='.$noncestr.'×tamp='.$timestamp.'&url='.$url; 12 $this->str_test = $str; 13 // sha1()加密方式 14 $signature = sha1($str); 15 16 // 這個是微信公眾號的AppID 17 if($zjwx = $weixin['AppID']) { 18 $appID = $zjwx; 19 } else { 20 $appID = ''; 21 } 22 23 $res = array( 24 'str_test' => $str, 25 'url'=>$url, 26 'signature'=>$signature, 27 'nonceStr'=>$noncestr, 28 'timestamp'=>$timestamp, 29 'jsapi_ticket'=>$jsapi_ticket, 30 'appId' => $appID 31 ); 32 } 33 exit(json_encode($res)); 34 } 35 }