1. 程式人生 > >微信JSSDK分享--挖坑填坑之小結

微信JSSDK分享--挖坑填坑之小結

file com 附錄 success 成功 文檔 -i 是把 n)

  最近參與微信服務號小項目的開發,關於微信分享,我是只知其功能,並沒深入了解其中的彎彎道道。雖然項目中不是我負責微信分享這一塊(因為我也不太會),但是團隊在這個功能上,那可是說多了都是淚,耗費了超級多的時間:一句話就是加班加點的挖坑,制造解決不了的bug,然後加班加點的找問題所在,去解決。主要是我們對於微信分享這塊的了解並不深入,沒想到的太多。

  當時一直分享不成功,我們前端一直以為是我們的js代碼寫的有問題,誰知道最大的問題是配置問題:

  一、不再同一個服務號。

  因為微信端,為了識別用戶,每個用戶針對每個公眾號會產生一個安全的OpenID,如果需要在多公眾號、移動應用之間做用戶共通,則需前往微信開放平臺,將這些公眾號和應用綁定到一個開放平臺賬號下,綁定後,一個用戶雖然對多個公眾號和應用有多個不同的OpenID,但他對所有這些同一開放平臺賬號下的公眾號和應用,只有一個UnionID,可以在用戶管理-獲取用戶基本信息(UnionID機制)文檔了解詳情。

  二、分享的鏈接有&符,我們沒有做處理

  三、JS接口安全域名設置,沒有設置白名單。

  今天團隊的大神,特別針對微信分享這個功能,對於其中會遇到的問題進行了總結和講解,我這才對微信分享,有了更深入的認識和了解。記性不好,聽完怕忘,得來個聽後記錄啊。

  雖然微信提供了JSSDK,但是這不意味著你可以用自定義的按鈕來直接打開微信的分享界面,這套JSSDK只是把微信分享接口的內容定義好了,實際還是需要用戶點擊右上角的菜單按鈕進行主動的分享,用戶點開分享界面之後,出現的內容就會是你定義的分享標題、圖片和鏈接

  JSSDK使用步驟:

  1.步驟一:綁定域名

  2.步驟二:引入js

  技術分享

  3.步驟三:通過config接口註入權限驗證配置

  技術分享

  4.步驟四:通過ready接口處理成功驗證

  技術分享

  5. 步驟五:通過error接口處理失敗問題 // config信息驗證失敗會執行error函數,如簽名過期導致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數中查看,對於SPA可以在這裏更新簽名。

  技術分享

  寫到這裏,其實已經跟前端沒多大事了,剩下的就是關於公眾號的配置。但是當時我們前端還一直以為是自己js的錯誤。。(js詳見最後)

  配置大綱:

  技術分享

  詳細步驟:  

  1.設置JS接口安全域名。

  這裏填寫的是一級域名,不帶www和http。最多可以設置三個域名。設置完後點擊確定。(多說一句,相比以前的分享沒有任何域名限制,這裏設置安全域名,目的是為了當發現此公眾平臺發現誘導分享行為時,可以根據此域名追溯到所有分享出去的鏈接,以及通過這些鏈接增加的粉絲。這樣,微信就可以牢牢控制了你的微信平臺,一旦發現違規,讓分享鏈接失效,刪除掉誘導行為增加的粉絲,是瞬間就可以完成的。因此,微信平臺的開發者,一定要合理來使用分享功能,不要因小失大。等到你的微信平臺被封,估計哭都來不及)

  技術分享

  2.在開發者中心中獲取你的AppID和AppSecret,接下來在獲取令牌時,需要這兩個信息。

  技術分享

  3.獲取令牌

技術分享

unction wx_get_token() {
    $token = S(‘access_token‘);
    if (!$token) {
        $res = file_get_contents(‘https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=‘            .‘你的AppID‘.‘&secret=‘            .‘你的AppSecret‘);
        $res = json_decode($res, true);
        $token = $res[‘access_token‘];
        // 註意:這裏需要將獲取到的token緩存起來(或寫到數據庫中)
        // 不能頻繁的訪問https://api.weixin.qq.com/cgi-bin/token,每日有次數限制
        // 通過此接口返回的token的有效期目前為2小時。令牌失效後,JS-SDK也就不能用了。
        // 因此,這裏將token值緩存1小時,比2小時小。緩存失效後,再從接口獲取新的token,這樣
        // 就可以避免token失效。
        // S()是ThinkPhp的緩存函數,如果使用的是不ThinkPhp框架,可以使用你的緩存函數,或使用數據庫來保存。
        S(‘access_token‘, $token, 3600);
    }
    return $token;
}
註意:返回的access_token長度至少要留夠512字節。接口返回值:
{"access_token":"ACCESS_TOKEN","expires_in":7200}
{"access_token":"vdlThyTfyB0N5eMoi3n_aMFMKPuwkE0MgyGf_0h0fpzL8p_hsdUX8VGxz5oSXuq5dM69lxP9wBwN9Yzg-0kVHY33BykRC0YXZZZ-WdxEic4","expires_in":7200}

  4.獲取jsapi的ticket。jsapi_ticket是公眾號用於調用微信JS接口的臨時票據。正常情況下,jsapi_ticket的有效期為7200秒,通過access_token來獲取。

function wx_get_jsapi_ticket(){
    $ticket = "";
    do{
        $ticket = S(‘wx_ticket‘);
        if (!empty($ticket)) {
            break;
        }
        $token = S(‘access_token‘);
        if (empty($token)){
            wx_get_token();
        }
        $token = S(‘access_token‘);
        if (empty($token)) {
            logErr("get access token error.");
            break;
        }
        $url2 = sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi",
            $token);
        $res = file_get_contents($url2);
        $res = json_decode($res, true);
        $ticket = $res[‘ticket‘];
        // 註意:這裏需要將獲取到的ticket緩存起來(或寫到數據庫中)
        // ticket和token一樣,不能頻繁的訪問接口來獲取,在每次獲取後,我們把它保存起來。
        S(‘wx_ticket‘, $ticket, 3600);
    }while(0);
    return $ticket;
}
接口返回值:
{"errcode":0,"errmsg":"ok","ticket":"sM4AOVdWfPE4DxkXGEs8VMKv7FMCPm-I98-klC6SO3Q3AwzxqljYWtzTCxIH9hDOXZCo9cgfHI6kwbe_YWtOQg","expires_in":7200}

  5.簽名,將jsapi_ticket、noncestr、timestamp、分享的url按字母順序連接起來,進行sha1簽名。 noncestr是你設置的任意字符串。 timestamp為時間戳。

$timestamp = time();
$wxnonceStr = "任意字符串";
$wxticket = wx_get_jsapi_ticket();
$wxOri = sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s",
$wxticket, $wxnonceStr, $timestamp,
       ‘要分享的url(從http開始,如果有參數,包含參數)‘
);
$wxSha1 = sha1($wxOri);

  

  js代碼:

var shareData = {
    shareTitle:"",
    shareContent:"",
    shareUrl:location.href,
    imgUrl:"",
    success:function(){
        alert(‘分享成功!‘);
    }
};
function wxConfig () {
    $.ajax({
     // 此處的location.href必須做處理,一個大坑,因為如果url中有&這個特殊符號,微信端分享就不會成功。
url: "http://oa.zhmf.com/api/wx/wxconfig?url=" + location.href, method: ‘get‘, success: function (data) { var wxdataObj = {}; if(typeof data == "string" && data.indexOf("{")!=-1){ wxdataObj = JSON.parse(data); }else{ wxdataObj = data; } wx.config({ debug: false, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。 appId: wxdataObj.AppId||wxdataObj.appId, // 必填,公眾號的唯一標識 timestamp: wxdataObj.Timestamp||wxdataObj.timestamp, // 必填,生成簽名的時間戳 nonceStr: wxdataObj.NonceStr||wxdataObj.nonceStr, // 必填,生成簽名的隨機串 signature: wxdataObj.Signature||wxdataObj.signature, // 必填,簽名,見附錄1 jsApiList: [‘chooseImage‘, ‘uploadImage‘,‘onMenuShareTimeline‘, ‘onMenuShareAppMessage‘,"hideAllNonBaseMenuItem","showAllNonBaseMenuItem"], // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2 }); wx.error(function (res) { //console.log(‘res‘, res); }); }, error: function (data) { //console.log(‘error‘, data); } }); wx.ready(function () { wx.onMenuShareTimeline({ title: shareData.shareTitle, // 分享標題 link: shareData.shareUrl, // 分享鏈接 imgUrl: shareData.shareIcon, // 分享圖標 success: shareData.success// 用戶確認分享後執行的回調函數 }); wx.onMenuShareAppMessage({ title: shareData.shareTitle, // 分享標題 desc: shareData.shareContent, // 分享描述 link: shareData.shareUrl, // 分享鏈接 imgUrl: shareData.shareIcon, // 分享圖標 success: shareData.success// 用戶確認分享後執行的回調函數 });
     // 此處是微信禁用 if(location.href.indexOf("tinysite.html")==(-1)){ wx.hideAllNonBaseMenuItem(); } }); }; function isWeiXin(){ var ua = navigator.userAgent.toLowerCase(); if(ua.match(/MicroMessenger/i)=="micromessenger") { return true; } else { return false; } }//判斷是否在微信打開 //若果是微信就拉取微信權限 if(isWeiXin()){ wxConfig (); } //從url裏取值var urlData = getUrlData(["userId","fromSource"]); //使用 urlData.userId,urlData.fromSource function getUrlData (arr){ var dataArr = {}; for(var i = 0; i < arr.length; i++){ var urlList = decodeURIComponent(location.href).split("&"); for(var j = 0; j < urlList.length; j++){ if(urlList[j].indexOf(arr[i]+"=") != (-1)){ var data = urlList[j].slice(urlList[j].indexOf(arr[i]+"=")+arr[i].length+1); dataArr[arr[i]] = data; } } } return dataArr; }

  如果是多個頁面都分享自定義的標題和描述:

var share = {
            title: document.title,
            discription: document.discription,
            imgurl: "",
            url: location.href,
            success: function () {
                alert(‘分享成功!‘);
            }
        };
        if (data) {
            for (v in data) {
                share[v] = data[v] || share[v];
            }
        }   

  

  

微信JSSDK分享--挖坑填坑之小結