集成微信 JSSDK(使用微信分享的 API)
最近有个需求,就是在微信分享官网的时候,需要能定制标题,描述和 logo。
经过调查发现,微信现在不再支持通过在页面上设置图片的形式来设置 logo(亲测,经过验证),而是只能通过绑定公众号,然后通过微信的公众平台的 API 来定制这些内容。
下面就展示如何一步一步的实现这个集成:
首先我们需要有个域名,然后将这个域名绑定到微信公众号。这里要分两种情况:
入口:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
直接用你自己的微信扫码登录即可。登录之后你会看到这样一个配置:
在这里你需要把你的域名填入,需要特别强调的是,这里需要填入的是域名而非 URL。所以,请把http://
, https://
以及一般在 URL 最后的反斜杠/
都去掉。
特别强调,在测试账号下,域名可以没有备案,所以你可以看到我给的例子中使用的是ngrok生成的测试链接。同时测试账号下,这个域名对应的服务也不需要经过微信网页授权验证。
在需要调用 JS 接口的页面引入如下 JS 文件,(支持 https):http://res.wx.qq.com/open/js/jweixin-1.6.0.js
引入这个文件之后,来自微信的 JS 对象wx
将会全局可用,下面会看到如何使用。
这里需要先明白我们为什么需要权限验证,以及背后的原理是怎么回事。
我们回过头看第一步所做的事情,我们把网站的域名绑定到了一个公众号。那么我们在分享这个网页的时候,如果微信发现这个网页调用了微信的 API,那么微信就需要验证,这个网页是不是跟其绑定的公众号所配置的 JS 安全与名对应的网站。如果是,微信才会响应 API 的调用,否则拒绝。
下面我们来看看权限验证的接口wx.config
:
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
debug: true
,这个只能在测试的时候开启,如果上线,请务必关掉
timestamp
这个就是一个数字字符串格式的时间戳,没有什么特别的要求,但是请务必保证和生成签名时候使用的是一致的。
nonceStr
这个就是一个随机的字符串,没有什么特别的要求,但是请务必保证和生成签名的时候使用的是一致的。
signature
这个就是签名,这里需要特别强调的是这个签名是不能在前端代码完成的,否则微信会认为其无效,具体微信怎么实现的不清楚。所以这里要分两种情况,如果你是一个正常的 web 应用,那么在后端生成签名,通过适合你的方式传递到前端,然后再调用这个接口认证。如果是静态网站,那么你只能通过一个后端的 API 来返回这个签名,然后前端通过 ajax 来调用这个 API,获取签名。我的情况就是第二种。
上一步我们只是在做权限验证,相当于找微信确认我们是否有资格调用 API,如果通过了验证,我们才会被允许调用 API。这里我们将看到如何调用 API。
微信提供了一个认证成功之后会执行的钩子函数wx.ready()
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
所有的对 API 的调用都必须放在这个钩子函数中,否则因为权限认证接口是异步的,API 调用可能不会成功。
微信提供了一个认证失败之后会执行的钩子函数wx.error()
wx.error(function(res){
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
生成签名,就像上面说到的,需要在后端完成。具体算法是怎么样的,我们继续看。
参与签名的字段包括 noncestr(随机字符串), 有效的 jsapi_ticket, timestamp(时间戳), url(当前网页的 URL,不包含#及其后面部分)
这里面有一个新字段我们没有聊过jsapi_ticket,这个是什么呢?它类似于一个我们日常生活中,使用到的票,火车票,电影票等。微信将jsapi_ticket视作调用微信 JS API 的票据,只有你拥有了票,你才能调用。
那么怎么获取这个票呢?
方法如下:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
,这里又多了一个新的参数access_token
access_token又是什么呢?
access_token 是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用 access_token。
这里我们可以这样理解,你去游乐园玩,你需要一个入场的票,这个就是access_token,你可以通过它玩游乐场的一些项目。但是某些特别的项目你需要单独再买票,这个就是jsapi_ticket。
你可以通过下面的链接获取access_token:
https 请求方式:GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
至此我们拿到了生成签名的所有参数,接下来我们需要把这些签名排个序,这个排序的规则是根据参数名字的 ASCII 码从小到大排序,就像这样:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
最后对这个字符串进行 sha1 签名:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
最后我附上完整的代码供对照理解:
function registerWechatSharingApi() {
var url=window.location.href.split('#')[0]
$.ajax({
method: "get",
url: "<后端接口返回signature>?current_site_url="+url,
dataType: "json",
success: function(data){
wx.config({
debug: false,
appId: data.appId,
timestamp: data.timestamp,
nonceStr: data.noncestr,
signature: data.signature,
jsApiList: [
"onMenuShareTimeline",
"onMenuShareAppMessage",
"onMenuShareWeibo",
"onMenuShareQZone"
]
});
},
error:function(data){
console.log("Fetch WX signature failed")
}
});
wx.ready(function (){
console.log("WX config verify success")
var shareData = {
title: document.querySelector('title').innerText.replace(/\n|\r/g, ""),
desc: document.querySelector("meta[name='description']").getAttribute('content'),
link: window.location.href,
imgUrl: "<图片的地址>"
};
wx.onMenuShareAppMessage(shareData);
wx.onMenuShareTimeline(shareData);
wx.onMenuShareWeibo(shareData);
wx.onMenuShareQZone(shareData);
});
wx.error(function(res){
console.log("WX config verify failed");
});
}
registerWechatSharingApi()