基于nodejs 的微信 JS-SDK 简单应用

2015 是 Hybrid App 崛起之年 ,Web App 和 Native App 各有其强大之处,也有着致命的缺点,人们一边追求native流畅的用户体验,一边同时期望产品能够快速的迭代更新,Hybrid 成为必然的趋势。

鹅厂一马当先,发布了业内震惊一时的 JS-SDK , 这对于基于微信的h5开发者来说简直是如降甘露,从此开发者们告别了用箭头来提示右上角可以分享,并且随时可以使用微信的原生能力,微信变成了一个超级浏览器。

一、准备工作

1.在微信公众平台申请测试账号,并设置好好 JS 接口安全域名 (注:域名必须可以外网访问

2.查看微信开发者文档 (http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html)

 

二、开始编码

使用微信 sdk 必须自己实现微信的签名算法。

大概需要4个步骤:

1.获取 access_token;

2.根据 access_token 获取 jsapi_ticket

3. 根据 appId(公众号唯一id)、noncestr(随机字符串)、timestamp(时间戳)、url(当前页面完整url,不包括#aaa=bbb) 通过sha1算法签名

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)

});

至此,基本功能已经完成。附上效果图

基于nodejs 的微信 JS-SDK 简单应用基于nodejs 的微信 JS-SDK 简单应用基于nodejs 的微信 JS-SDK 简单应用

踩的坑:

1.签名算法不一致: 通过 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 验证算法正确性

2.url 必须完全一致,并且外网可访问。 将代码部署到 BAE ,或者其他应用引擎服务器上。

3.timestamp 需要精确到秒。

 

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

你可能感兴趣的:(nodejs)