nodejs进行微信公众号全栈开发

5、获取jssdk,进行微信内置网页开发

2017-10-17  本文已影响0人  伯纳乌的追风少年

正常情况下,js是不可以直接操作原生App的,但微信作为一款原生App,它提供了一套接口,允许前端工程师通过js来调用原生App的一些功能,我们只需要按照约定好的方式使用js调用的话,就可以使用微信原生的一些功能,如:拍照、相册、语音、分享、地理位置、扫一扫等功能。
但是在使用jssdk之前,还需要按照JS-SDK使用权限签名算法进行校验,只有校验通过,才可以使用jssdk提供的接口。

一、JS-SDK后台接口的开发

在开发JS-SDK接口之前,我们先要在后台配置一个JS接口安全域名:



测试号的话,在此配置。



注意,这里是域名,而不是url地址,如果带了“http://”的话,就会配置不成功。

配置好JS安全域名后,我们便可以进行JS-SDK接口的开发了。
js-sdk的接口需要返回以下数据:

{
  appId:appId,
  noncestr:noncestr,
  timestamp:timestamp,
  signature:signature
}

其中appId是我们已经在可以在后台知道的,而其他三个参数需要我们根据已有的信息进行生成。
首先, 创建noncestr参数:

function createNonceStr(){
  const chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  const length=chars.length;
  let str='';
  for (let i = 0; i < length; i++) {
    str += chars.substr(Math.round(Math.random()*length),1)
  };
  return str;
}

然后创建timestamp

const timestamp = Math.round(Date.now() / 1000)

还剩一个参数就是 signature了。
这个 signature获得起来比较复杂了,要想获得signature的话,先要获得jsapi_ticket、noncestr、timestamp、url。
noncestr、timestamp这两个参数我们可以自己生成,url在前端调用的时候会传进来,而jsapi_ticket则需要我们调用接口生成。
调用jsapi_ticket的接口地址为:https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=${accessToken}
jsapi_ticket接口和accessToken接口一样,都有2000次的调用限制,因此也需要和accessToken一样做7200秒的缓存。
而jsapi_ticket的接口调用还需要传入accessToken作为参数,所以还需要调用获取accessToken的接口。
所以我们的流程是:
1、获取accessToken
2、获取jsapi_ticket
3、获取noncestr、timestamp、url
4、生成signature
5、返回js-sdk接口数据
我们把这些封装成一个jssdk对象:

var crypto = require('crypto');
var request= require('request');
var fs = require('fs');

function JSSDK(appId,appSecret){
    this.appId=appId;
    this.appSecret=appSecret;
}

JSSDK.prototype={
    getSignPackage:function(url,done){
        const instance=this
        this.getJsApiTicket(function(err,jsApiTicket){
            if(err){
                return done(err)
            }

            const timestamp = Math.round(Date.now() / 1000)
            const noncestr = instance.createNonceStr()
            const rawString = `jsapi_ticket=${jsApiTicket}&noncestr=${noncestr}&timestamp=${timestamp}&url=${url}`
            const hash = crypto.createHash('sha1');
            const signature = hash.update(rawString).digest('hex');

            done(null,{
                appId:instance.appId,
                noncestr:noncestr,
                timestamp:timestamp,
                url:url,
                signature:signature
            })
        })
    },
    getJsApiTicket:function(done){
        const cacheFile='.jsApiTicket.json'
        const data=this.readCacheFile(cacheFile);
        const time=Math.round(Date.now() / 1000);
        const instance =this;
        if(typeof data.expireTime === 'undefined' || data.expireTime < time){
            instance.getAccessToken(function(error,accessToken){
                if(error){
                    return done(error,null)
                }
                const url=`https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=${accessToken}`
                request.get(url,function(err,res,body){
                    if (err) {
                        return done(err,null)
                    };

                    try {
                        const data =JSON.parse(body);
                        instance.writeCacheFile(cacheFile,{
                            expireTime: Math.round(Date.now() / 1000) +7200,
                            jsApiTicket: data.ticket
                        })

                        done(null,data.ticket)
                    }catch(e){
                        done(e,null)
                    }

                })
            })
        }else{
            done(null,data.jsApiTicket)
        }

    },
    createNonceStr:function(){
        // return Math.random().toString(36).substr(2, 15);
        const chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        const length=chars.length;
        let str='';
        for (let i = 0; i < length; i++) {
            str += chars.substr(Math.round(Math.random()*length),1)
        };
        return str;
    },
    getAccessToken:function(done){
        const cacheFile = '.accesstoken.json';
    const instance = this;
    const data = instance.readCacheFile(cacheFile);
    const time = Math.round(Date.now() / 1000);

    if (typeof data.expireTime === 'undefined' || data.expireTime < time) {
        const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${this.appId}&secret=${this.appSecret}`;
        request.get(url, function (err, res, body) {
            if (err) {
                return done(err, null);
            }
            try {
                const data = JSON.parse(body);
                instance.writeCacheFile(cacheFile, {
                    expireTime: Math.round(Date.now() / 1000) + 7200,
                    accessToken: data.access_token,
                });

                done(null, data.access_token);
            } catch (e) {
                done(e, null);
            }
        });
    } else {
        done(null, data.accessToken);
    }
    },
    readCacheFile:function(filename){
        try {
            return JSON.parse(fs.readFileSync(filename));
        } catch (e){
            console.log("read file %s failed: %s",filename,e)
        }
        return {}
    },
    writeCacheFile:function(filename,data){
        return fs.writeFileSync(filename,JSON.stringify(data));
    },
}

const jssdk=new JSSDK('wxeee44dbd49e6139a','daad8a1466f76f6c6e98601d6179ec3b')


module.exports=jssdk

其中readCacheFile和writeCacheFile是读取和写入缓存文件时封装的方法。
我们在调用js-jdk接口的时候,需要引入这个模块:

var express = require('express');
var router = express.Router();
const jsSdk = require('../libs/jssdk')
router.get('/getJsSdk', function (req, res) {
    jsSdk.getSignPackage(req.query.url,function(err,signPackage){
        res.send(signPackage)
    })
});



二、调用JS-SDK接口的前端开发

后台将js-sdk接口开发完成后,将会提供给前端一个接口的地址,前端可以传入相应的参数进行调用,调用后用拿到的数据进行验证。
1、引入script标签:<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
2、调用开发好的sdk接口,需要传入url作为参数,这个url是需要先截取“#”前面的部分才行
3、拿到数据后,进行wx.config进行配置:

wx.config({
                    debug: false,
                    appId: data.appId, 
                    timestamp: data.timestamp,
                    nonceStr: data.noncestr,
                    signature: data.signature,
                    jsApiList: ['showMenuItems','onMenuShareTimeline',   'onMenuShareAppMessage','onMenuShareQQ'] //功能列表,我们要使用JS-SDK的什么功能
});

4、配置成功,则我们可以拿到jsApiList中列出的所有js-sdk原生功能调用权限

具体代码如下:
我们新建一个文件index.html
文件内容为:

<html>
<head>
    <title>js-sdk</title>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script type="text/javascript">
    ;(function($){
        $.ajax({
            type:'get',
            url:"http://wxnode.xiaoxiekeke.com/verify/getJsSdk",
      data: {
        url: '' + window.location.href.split('#')[0]
      },
            contentType: "application/json",
            success:function(data){
                wx.config({
                    debug: false,
                    appId: data.appId, 
                    timestamp: data.timestamp,
                    nonceStr: data.noncestr,
                    signature: data.signature,
                    jsApiList: ['showMenuItems','onMenuShareTimeline', 'onMenuShareAppMessage','onMenuShareQQ'] //功能列表,我们要使用JS-SDK的什么功能
                });
                wx.ready(function() {
                    wx.showMenuItems({
                      menuList: ['menuItem:share:appMessage' , 'menuItem:share:timeline' ,'menuItem:share:qq'] // 要显示的菜单项,所有menu项见附录3
                  });
                })
            },
            error:function(err){
        console.log(err);
      }
        })
    })(jQuery);
</script>
</body>

</html>

如何查看是否成功?我们可以使用微信开发者工具进行调试,打开微信开发者工具,输入index.html页面所在所在的地址:



当我们看到:“config:ok”的时候证明配置验证成功了,此时,我们前端工程师便可以在网页中通过jssdk的文档进行公共号内嵌网页的开发了。

另附上:jssdk说明文档

上一篇下一篇

猜你喜欢

热点阅读