这几天要做一个H5的页面,之前没做。对我来讲也是一次对新领域的打仗。空话不多说来讲说用node做服务端挪用微信JS SDK碰到的坑。
起首讲一下思绪:
绑定域名
引入JS文件
经由过程config接口注入权限考证设置
wx.config({
debug: true,
appId: '', // 必填,民众号的唯一标识
timestamp: , // 必填,天生署名的时候戳
nonceStr: '', // 必填,天生署名的随机串
signature: '',// 必填,署名,见附录1
jsApiList: [] // 必填,须要运用的JS接口列表,一切JS接口列表见附录2
});
今后就是经由过程ready接口处置惩罚胜利考证、经由过程error接口处置惩罚失利考证。微信JS-SDK都有申明不做赘述。
Node挪用微信JS-SDK实践
须要装置一下模块供我们运用:
npm install sha1
这个哈希1模块是处置惩罚对字符的哈希加密,天生signature
npm install redis
这个人人都懂,用来做对access_token、jsapi_ticket的存储而且设定存在时候7200s。(由于7200s今后微信返回的值才会转变,而且微信划定天天限定2000的接见次数);
假如运用co库的话
npm install co
上风
能够削减对微信sdk服务器接见的次数,提拔机能。同时对接见的次数限定做了最大的优化处置惩罚。
起首建一个wechatConfig.js用来寄存appid,appsecret
module.exports = {
appid : '',//民众号的appId,能够在民众平台上找到,-。-本身找。
appsecret : ''//民众号的appsecret
};
竖立getWebToken.js 用来返回access_token,由于这个是异步返回一个promise
'use strict';
const request = require('request');
const qs = require('querystring');
const config = require('./../wechatConfig');
function getToken() {
let reqUrl = 'https://api.weixin.qq.com/cgi-bin/token?';
let params = {
grant_type: 'client_credential',
appid: config.appid,
secret: config.appsecret
};
let options = {
method: 'get',
url: reqUrl+qs.stringify(params)
};
console.log(options.url);
return new Promise((resolve, reject) => {
request(options, function (err, res, body) {
if (res) {
console.log(body)
resolve(body);
} else {
reject(err);
}
})
})
}
module.exports = getToken;
param的递次肯定不能错!!!这个很重要不然会证书会认证失利!这个坑我整了1天赋爬出来。
竖立一个getJsApiData.js 文件用来做为重要的controller返回效果返回给client
/**
* Created by caozheng on 2016/11/24.
*/
'use strict';
const fs = require('fs');
const request = require('request');
const getToken = require('./getWebToken');
const sha1 = require('sha1');
function getJsApiTicket() {
return new Promise((resolve, reject) => {
getToken().then(function (body) {
body = JSON.parse(body);
var token = body.access_token;
var reqUrl = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + token + '&type=jsapi';
let options = {
method: 'get',
url: reqUrl
};
request(options, function (err, res, body) {
if (res) {
resolve(body);
} else {
reject(err);
}
})
}).catch(function (err) {
throw (err)
});
})
}
//noncestr
function getNonceStr () {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for(var i = 0; i < 16; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
//timestamp
function getTimestamp() {
var time = String(new Date().valueOf());
return time.substr(0, time.length-3);
}
function getSign(jsApiTicket, noncestr, timestamp, url) {
console.log("******************");
console.log(jsApiTicket);
var sortData = "jsapi_ticket=" + jsApiTicket + "&noncestr=" + noncestr + "×tamp=" + timestamp + "&url=" + url;
return sha1(sortData);
}
//返回数据分别为sign, timestamp, noncestr
function getJsApiData(clientUrl) {
let noncestr = getNonceStr();
let timestamp = getTimestamp();
return getJsApiTicket().then(data => {
return [getSign(JSON.parse(data).ticket, noncestr, timestamp, clientUrl), timestamp, noncestr];
})
}
module.exports = getJsApiData;
在路由处增加进口
/*微信返回sdk参数*/
router.post('/wechat',function (req, res) {
var clientUrl = req.body.url;
getJsApiData(clientUrl).then(data => {
res.send({signature: data[0], timestamp: data[1], nonceStr: data[2]});
});
});
注重:这里从client传过来的url肯定是动态猎取的location.href.split(‘#’)[0],而且不能带有#号,由于分享一篇文章今后微信会在链接后加参数。
运用redis缓存access_token、jsapi_ticket
竖立一个redis.js文件,由于这里只须要存储功用。
/**
* Created by caozheng on 2016/11/24.
*/
var db = {};
var redis = require('redis');
var options = {
host : '', // 这里不须要诠释吧
port : '6379', // 这里也不须要
password : '', // 这个论英文的重要性
db : 2 //db存储的位置
};
var client = redis.createClient(options);
client.on('ready',function(err){
console.log('ready');
});
client.on("error", function (err) {
console.log("Error :" , err);
});
client.on('connect', function(){
console.log('Redis衔接胜利.');
});
/**
* 增加string范例的数据
* @param key 键
* @params value 值
* @params expire (逾期时候,单元秒;可为空,为空示意不逾期)
* @param callBack(err,result)
*/
db.set = function(key, value, expire, callback){
client.set(key, value, function(err, result){
console.log(key);
console.log(value);
if (err) {
console.log(err);
callback(err,null);
return;
}
if (!isNaN(expire) && expire > 0) {
client.expire(key, parseInt(expire));
}
callback(null,result)
})
};
/**
* 查询string范例的数据
* @param key 键
* @param callBack(err,result)
*/
db.get = function(key, callback){
client.get(key, function(err,result){
if (err) {
console.log(err);
callback(err,null);
return;
}
callback(null,result);
});
};
module.exports = db;
总结:这里也能够写成异步! express能够运用co库,KOA的话那就不必看我写的了…
在getJsApiData.js中的getJsApiTicket函数中增加redis存储,读取。同时须要引入redis.js
const db = require('./../../db/radis');
var res = {
access_token :'',
ticket : ''
} // 这里为了和大众接口同步把数
co(function* (){
// 援用co库
var result = yield {
access_token : db.get("access_token"),
ticket : db.get("ticket")
}
// 推断redis中是不是存在access_token、ticket
if(result.access_token && result.ticket){
return result // 返回存储中的ticket的值
}else{
// 这里是之前代码 -> getJsApiTicket 中返回promise的要领
}
})
总结 : 这只是个示例代码的详细完成照样看场景。