正常情况下,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}×tamp=${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说明文档
网友评论