基於nodejs 的微信 JS-SDK 簡單應用

2015 是 Hybrid App 崛起之年 ,Web App 和 Native App 各有其強大之處,也有着致命的缺點,人們一邊追求native流暢的用戶體驗,一邊同時指望產品可以快速的迭代更新,Hybrid 成爲必然的趨勢。html

鵝廠身先士卒,發佈了業內震驚一時的 JS-SDK , 這對於基於微信的h5開發者來講簡直是如降甘露,今後開發者們告別了用箭頭來提示右上角能夠分享,而且隨時可使用微信的原生能力,微信變成了一個超級瀏覽器。前端

1、準備工做

1.在微信公衆平臺申請測試帳號,並設置好好 JS 接口安全域名 (注:域名必須能夠外網訪問git

2.查看微信開發者文檔 (http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html)github

 

2、開始編碼

使用微信 sdk 必須本身實現微信的簽名算法。ajax

大概須要4個步驟:算法

1.獲取 access_token;json

2.根據 access_token 獲取 jsapi_ticketapi

3. 根據 appId(公衆號惟一id)、noncestr(隨機字符串)、timestamp(時間戳)、url(當前頁面完整url,不包括#aaa=bbb) 經過sha1算法簽名promise

4.將信息返回給前端 , 設置wx.config。瀏覽器

因爲獲取access_token 和 jsapi_ticket 的接口都有訪問限制,因此明確指出須要第三方作緩存處理。此處咱們緩存jsapi_ticket 就能夠了。

/config/wechat.cfg.js

module.exports = {
    grant_type: 'client_credential',
    appid: 'xxxxxxxxxxxxxxx',
    secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxx',
    noncestr:'Wm3WZYTPz0wzccnW',
    accessTokenUrl:'https://api.weixin.qq.com/cgi-bin/token',
    ticketUrl:'https://api.weixin.qq.com/cgi-bin/ticket/getticket',
    cache_duration:1000*60*60*24 //緩存時長爲24小時
}

最主要部分是簽名:

signature.js

var request = require('request'),
    cache = require('memory-cache'),
    sha1 = require('sha1'),
    config = require('../config/wechat.cfg');

exports.sign = function (url,callback) {
    var noncestr = config.noncestr,
        timestamp = Math.floor(Date.now()/1000), //精確到秒
        jsapi_ticket;
    if(cache.get('ticket')){
        jsapi_ticket = cache.get('ticket');
        console.log('1' + 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + noncestr + '&timestamp=' + timestamp + '&url=' + url);
        callback({
            noncestr:noncestr,
            timestamp:timestamp,
            url:url,
            jsapi_ticket:jsapi_ticket,
            signature:sha1('jsapi_ticket=' + jsapi_ticket + '&noncestr=' + noncestr + '&timestamp=' + timestamp + '&url=' + url)
        });
    }else{
        request(config.accessTokenUrl + '?grant_type=' + config.grant_type + '&appid=' + config.appid + '&secret=' + config.secret ,function(error, response, body){
            if (!error && response.statusCode == 200) {
                var tokenMap = JSON.parse(body);
                request(config.ticketUrl + '?access_token=' + tokenMap.access_token + '&type=jsapi', function(error, resp, json){
                    if (!error && response.statusCode == 200) {
                        var ticketMap = JSON.parse(json);
                        cache.put('ticket',ticketMap.ticket,config.cache_duration);  //加入緩存
                        console.log('jsapi_ticket=' + ticketMap.ticket + '&noncestr=' + noncestr + '&timestamp=' + timestamp + '&url=' + url);
                        callback({
                            noncestr:noncestr,
                            timestamp:timestamp,
                            url:url,
                            jsapi_ticket:ticketMap.ticket,
                            signature:sha1('jsapi_ticket=' + ticketMap.ticket + '&noncestr=' + noncestr + '&timestamp=' + timestamp + '&url=' + url)
                        });
                    }
                })
            }
        })
    }
}

因爲只是簡單的demo , 也就沒有采用promise,而是採用的普通的回調。

 

客戶端部分

document.getElementById('refresh').onclick = function(){location.reload();}

/**
 *  如下內容多摘自官方demo
 *
**/
wx.config({
    debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。
    appId: appId, // 必填,公衆號的惟一標識
    timestamp: timestamp, // 必填,生成簽名的時間戳
    nonceStr: nonceStr, // 必填,生成簽名的隨機串
    signature: signature,// 必填,簽名,見附錄1
    jsApiList: ['checkJsApi',
        'onMenuShareTimeline',
        'onMenuShareAppMessage',
        'onMenuShareQQ',
        'onMenuShareWeibo',
        'hideMenuItems',
        'showMenuItems',
        'hideAllNonBaseMenuItem',
        'showAllNonBaseMenuItem',
        'translateVoice',
        'startRecord',
        'stopRecord',
        'onRecordEnd',
        'playVoice',
        'pauseVoice',
        'stopVoice',
        'uploadVoice',
        'downloadVoice',
        'chooseImage',
        'previewImage',
        'uploadImage',
        'downloadImage',
        'getNetworkType',
        'openLocation',
        'getLocation',
        'hideOptionMenu',
        'showOptionMenu',
        'closeWindow',
        'scanQRCode',
        'chooseWXPay',
        'openProductSpecificView',
        'addCard',
        'chooseCard',
        'openCard'] // 必填,須要使用的JS接口列表,
});

wx.ready(function(){
 // 1 判斷當前版本是否支持指定 JS 接口,支持批量判斷
  document.querySelector('#checkJsApi').onclick = function () {
    wx.checkJsApi({
      jsApiList: [
        'getNetworkType',
        'previewImage'
      ],
      success: function (res) {
        alert(JSON.stringify(res));
      }
    });
  };

   // 2. 分享接口
  // 2.1 監聽「分享給朋友」,按鈕點擊、自定義分享內容及分享結果接口
  document.querySelector('#onMenuShareAppMessage').onclick = function () {
    wx.onMenuShareAppMessage({
      title: '互聯網之子',
      desc: '在長大的過程當中,我才慢慢發現,我身邊的全部事,別人跟我說的全部事,那些所謂原本如此,註定如此的事,它們其實沒有非得如此,事情是能夠改變的。更重要的是,有些事既然錯了,那就該作出改變。',
      link: 'http://movie.douban.com/subject/25785114/',
      imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
      trigger: function (res) {
        // 不要嘗試在trigger中使用ajax異步請求修改本次分享的內容,由於客戶端分享操做是一個同步操做,這時候使用ajax的回包會尚未返回
        alert('用戶點擊發送給朋友');
      },
      success: function (res) {
        alert('已分享');
      },
      cancel: function (res) {
        alert('已取消');
      },
      fail: function (res) {
        alert(JSON.stringify(res));
      }
    });
    alert('已註冊獲取「發送給朋友」狀態事件');
  };

    // 5 圖片接口
  // 5.1 拍照、本地選圖
  var images = {
    localId: [],
    serverId: []
  };
  document.querySelector('#chooseImage').onclick = function () {
    wx.chooseImage({
      success: function (res) {
        images.localId = res.localIds;
        alert('已選擇 ' + res.localIds.length + ' 張圖片');
      }
    });
  };
    // 5.2 圖片預覽
  document.querySelector('#previewImage').onclick = function () {
    wx.previewImage({
      current: 'http://img5.douban.com/view/photo/photo/public/p1353993776.jpg',
      urls: [
        'http://img3.douban.com/view/photo/photo/public/p2152117150.jpg',
        'http://img5.douban.com/view/photo/photo/public/p1353993776.jpg',
        'http://img3.douban.com/view/photo/photo/public/p2152134700.jpg'
      ]
    });
  };

    // 7.2 獲取當前地理位置
  document.querySelector('#getLocation').onclick = function () {
    wx.getLocation({
      success: function (res) {
        alert(JSON.stringify(res));
      },
      cancel: function (res) {
        alert('用戶拒絕受權獲取地理位置');
      }
    });
  };

    // 9 微信原生接口
  // 9.1.1 掃描二維碼並返回結果
  document.querySelector('#scanQRCode0').onclick = function () {
    wx.scanQRCode();
  };

});

wx.error(function(res){
    JSON.stringify(res)
});

至此,基本功能已經完成。附上效果圖

踩的坑:

1.簽名算法不一致: 經過 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 驗證算法正確性

2.url 必須徹底一致,而且外網可訪問。 將代碼部署到 BAE ,或者其餘應用引擎服務器上。

3.timestamp 須要精確到秒。

 

源碼:https://github.com/liaobin312716/wechat-sdk-demo/

相關文章
相關標籤/搜索