关于微信的jsdk的若干亲身实践之小结
前言:
业务来源:自主研发的手机app软件有分享文章到微信或者QQ以及微博的功能,而在微信中再次点击分享按钮的时候,情况就出现的不可把控了:
文章显示的缩略图不能正常显示;文章的简介不能显示……而我们领导的要求便是再次分享的时候,显示自己app的logo,于是就开始了微信jsdk的整天研究。(题外话:其实在去年,自己就看过微信jsdk文档,但是苦于研究不出什么名堂,而且当时是找了一种‘投机取巧’的方法,算是完美的解决了当时的需求,但是意外总是在不经意间就降临了,那天突然看见了微信公众号中说道:“
JSSDK自定义分享接口的策略调整
2017-03-29 微信团队 微信开发者
为规范自定义分享链接功能在网页上的使用,自2017年4月25日起,JSSDK“分享到朋友圈”及“发送给朋友”接口,自定义的分享链接,其域名或路径必须与当前页面对应的公众号JS安全域名一致,否则将调用失败。
例如,当前页面是 http://www.abc.com/123,其公众号对应的JS安全域名为 www.abc.com 以及 www.xyz.com,则分享自定义链接 http://www.abc.com/456 可以成功,分享 http://www.xyz.com/123 或 http://www.def.com/123 均将失败。
对于未接入微信JSSDK或已接入但JSSDK调用失败的网页,被用户分享时,分享卡片将统一使用默认缩略图和标题简介,不允许自定义。
接口完整用法请参考《微信JSSDK说明文档》,请开发者及时完成调整。”)
这样的突发情况就如晴天霹雳,让自己不得不面对再次拾起关于微信jsdk的研究。历经“山重水复”的过程,特地把踩过的坑粉分享出来,这样小伙伴们就不会陷入同样的错误中了(下面的版本是基于nodejs环境下的~)。
过程:
这是官方文档地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN,先看文档再上手;按照步骤,一步步进行;关于具体的文档中都有,小伙伴们仔细看文档肯定就能理解,接下来就只是说说自己在实现这个功能时,问题出在哪里吧……
1.注意点一:(首先配置js接口安全域名,即程序运行的网址是什么,需要下载的文件,官网上直接下载配置即可;配置完成后,可在“开发者中心”查看对应的接口权限);
2.在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js
- <script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
3.注意点二,也是最关键最核心的部分,因为如果这里配置成功,后面便可成功的调用微信粉分享接口,否则便失败;
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名,见附录1
jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
这便是需要配置的东西,下面谈谈心酸的踩坑经历:
1)timestamp //当前时间戳 这里是秒级别的时间戳格式
- let timestamp = parseInt( new Date().getTime()/1000);//秒级别
2)nonceStr //随机字符串 这里是保留长度为16的随机字符串
- let nonceStr = Math.random().toString(36).substr(2,16);//长度为16的随机字符串
3)signature ——> 重点来了!关于这个签名的取值,硬生生的耗费了自己很长很长时间,也是因为自己不够聪明,没看清楚文档写的,这里还是要感谢老大,昨晚陪自己加班快十点找问题,直到今早上终于完美解决掉。
关于动态产生的签名:
a.先使用appid,secret,通过get请求“https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret”,得到access_token;
b.用得到的access_token,再次通过get请求”https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='+access_token+'&type=jsapi”,最终得到jsapi_ticket;
c.签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。例如:
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义,得到signature。
即signature=sha1(string1)。
注意点:重点!
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。原本打算在项目中使用session来缓存这两个,最终在老大的知道下,这里使用的是redis存储缓存;
完整前台HTML页面代码:
- <script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
- <script>
- jQuery(function () {
- //页面初始化完成后,先post请求将当前页面的url传到后台,进行signature的计算,而这里一定记得要: encodeURIComponent()一下,去后台后在: decodeURIComponent(),要不就是频繁报“invalid signature"的错误
- jQuery.post("/share/getshare", {"url": encodeURIComponent(window.location.href.split('#')[0]),"t": new Date().getTime()}, function (result) {
- if (result.errno != 0) {
- alert("您当前的网络不稳定请稍后再试!");
- return;
- }
- var shareUrl = result.data.url;
- wx.config({
- debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
- appId: 'wxf919e3b61eca36ae', // 必填,公众号的唯一标识
- timestamp: result.data.timestamp, // 必填,生成签名的时间戳
- nonceStr: result.data.nonceStr, // 必填,生成签名的随机串
- signature: result.data.signature,// 必填,签名,见附录1
- jsApiList: ['onMenuShareAppMessage','onMenuShareTimeline','onMenuShareQQ','onMenuShareWeibo'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
- });
- wx.ready(function () {
- var title = "{{data.title}}";
- var desc = "{{data.scontent}}"?"{{data.scontent}}":"";
- var imgUrl = "http://static.gangguwang.com/image/2016/12/16/16/55/5853abfc101887000800111f.jpg";
- wx.onMenuShareTimeline({//“分享到朋友圈”
- title: title, // 分享标题
- link: shareUrl, // 分享链接
- imgUrl: imgUrl, // 分享图标
- success: function () {
- // 用户确认分享后执行的回调函数
- },
- cancel: function () {
- // 用户取消分享后执行的回调函数
- }
- });
- wx.onMenuShareAppMessage({//“分享给朋友”
- title: title, // 分享标题
- desc: desc, // 分享描述
- link: shareUrl, // 分享链接
- imgUrl: imgUrl, // 分享图标
- type: 'link', // 分享类型,music、video或link,不填默认为link
- dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
- success: function () {
- console.log('succ~');
- // 用户确认分享后执行的回调函数
- },
- cancel: function () {
- console.log('fail~');
- // 用户取消分享后执行的回调函数
- }
- });
- wx.onMenuShareQQ({//“分享到QQ”
- title: title, // 分享标题
- desc: desc, // 分享描述
- link: shareUrl, // 分享链接
- imgUrl: imgUrl, // 分享图标
- success: function () {
- // 用户确认分享后执行的回调函数
- },
- cancel: function () {
- // 用户取消分享后执行的回调函数
- }
- });
- wx.onMenuShareWeibo({//“分享到腾讯微博”
- title: title, // 分享标题
- desc: desc, // 分享描述
- link: shareUrl, // 分享链接
- imgUrl: imgUrl, // 分享图标
- success: function () {
- // 用户确认分享后执行的回调函数
- },
- cancel: function () {
- // 用户取消分享后执行的回调函数
- }
- });
- });
- });
- })
- </script>
- 后台的处理逻辑:
- //这里先要引入sha1依赖包
- //getshare方法便是获得动态签名的方法(这是基于node.js环境下的)
- async getshareAction(){
- //将前台得到的url先decodeURIComponent()一下再使用
- let url = decodeURIComponent(this.post().url);
- //当前时间戳
- let timestamp = parseInt( new Date().getTime()/1000);
- //随机字符串
- let nonceStr = Math.random().toString(36).substr(2,16);
- ////获取缓存信息 存在redis中,从 redis 里获取缓存(全局缓存jsapi_ticket -----> 有效期7200秒)
- let ticket = await think.cache('ticket_weixinshare_ywg', undefined, {type: 'redis'});
- let access_token = await think.cache('token_weixinshare_ywg', undefined, {type: 'redis'});
- let req = think.promisify(request.get);
- if(!access_token){//不存在
- let options1 = {//获取 acess_token
- url: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret',
- method: "get"
- };
- let res = await req(options1);
- access_token = JSON.parse(res.body).access_token;
- //设置缓存 access_token(这里是thinkjs的redis设置缓存的方法)
- await think.cache('token_weixinshare_ywg', access_token);
- }
- if(!ticket){
- let options2={//计算 jsapi_ticket
- url: 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='+access_token+'&type=jsapi',
- method: "get"
- };
- let res2 = await req(options2);
- if(JSON.parse(res2.body).errcode==0){
- ticket=JSON.parse(res2.body).ticket;
- //设置缓存 ticket
- await think.cache('ticket_weixinshare_ywg', ticket);
- }else{
- console.log('=========error==='+JSON.parse(res2.body).errmsg)
- }
- }
- //按照字段名的ASCII 码从小到大排序(字典序)
- let raw = async (args) =>{
- let keys = Object.keys(args);
- keys = keys.sort();
- let newArgs = {};
- keys.forEach(function (key) {
- newArgs[key.toLowerCase()] = args[key];
- });
- let string = '';
- for (let k in newArgs) {
- string += '&' + k + '=' + newArgs[k];
- }
- string = string.substr(1);
- return string;
- };
- let ret = {
- jsapi_ticket: ticket,
- nonceStr: nonceStr,
- timestamp: timestamp,
- url: url
- };
- let string1 = await raw(ret);
- //将得到的字符串进行sha1加密,然后返回将 wx.config()中所需要的值返回到前台页面
- let signature = sha1(string1);
- this.success({"timestamp":timestamp,"nonceStr":nonceStr,"signature":signature,"url":url});
- }
至此运行,便可以神清气爽的看见下面的提示:
而昨天一整天的情况便是:
而对于“invalid signature”的问题排查官方文档也给出了相应的介绍:
2.invalid signature签名错误。建议按如下顺序检查:
1.确认签名算法正确,可用 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。
2.确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。
3.确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。
4.确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。
5.确保一定缓存access_token和jsapi_ticket。
6.确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。
而自己按照步骤来实现的获取签名,也总是报错的根本原因就是url取得有问题,因此建议大家自己阅读文档,获取到页面的完整路径并先进行处理后再使用。(自己使用的页面完整url路径:http://127.0.0.1:8361/share?id=xxx).
4.成功获得签名后,便可以通过ready接口处理接下来的数据(关于这部分的介绍,文档中很详细,相信大家一看便知,就不多说了。)
后言:
关于掉微信分享接口,其实这个功能应该在年前就做好的,只是当时也是因为签名总是获取失败的原因而将此搁置,直至今天不得不重新开始研究,突然明白了“凡是出来混,总是要还的”这句至理名言的真理性。而自己遇到的这个问题,也希望以后不会再犯,还有可以用到的小伙伴们也能用上。
关于微信的jsdk的若干亲身实践之小结的更多相关文章
- 亲身实践 yui-compressor压缩js和css
最近很懒散,个人感情.家庭原因,没有动力去学东西,老是发誓要搞好前端工程化,老中断,唉!没有魄力! 最近老觉得这前端工程化有什么好的,东西那么多,还得学!直到前几天产品提了个优化,说搜索结果页跳商品详 ...
- 微信团队原创分享:iOS版微信的内存监控系统技术实践
本文来自微信开发团队yangyang的技术分享. 一.前言 FOOM(Foreground Out Of Memory),是指App在前台因消耗内存过多引起系统强杀.对用户而言,表现跟crash一样. ...
- 微信小程序开发入门与实践
基础知识---- MINA 框架 为方便微信小程序开发,微信为小程序提供了 MINA 框架,这套框架集成了大量的原生组件以及 API.通过这套框架,我们可以方便快捷的完成相关的小程序开发工作. MIN ...
- 微信小程序从入门到实践(一)-设置底部导航栏
微信小程序最多能加5个导航图标.因为我们只有两个默认页面,这里我们就添加两个导航图标 先看我们要达到的就是这么一个效果 接下来开始实践: (1)准备工作 找几个图标,将上述起好名字的图标 保存到 小程 ...
- 【腾讯Bugly干货分享】微信iOS SQLite源码优化实践
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57b58022433221be01499480 作者:张三华 前言 随着微信iO ...
- 微信分享jsdk接口
HTML文件 <!DOCTYPE html><html><head> <meta charset="utf-8"> <titl ...
- 微信小程序的初窥实践
最近,小程序正式上线,各企业都纷纷开发,本博主看下其中奥秘, 首先得去微信公众平台(https://mp.weixin.qq.com/)注册一个小程序账号(以前注册过公众号的账号不可使用) 备注:注册 ...
- 微信支付之手机H5支付实践
最近项目中支付部分涉及到微信支付,使用的是h5支付,官方文档中是没有demo的,所以摸着石头过河,将踩过的坑记录如下. 一 应用场景 H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前 ...
- 微信小程序“信用卡还款”项目实践
小程序概述 11月3日晚,微信团队对外宣布,微信小程序开放公测.开发者可登陆微信公众平台申请,开发完成后可以提交审核,公测期间暂不能发布. 我们前一段时间也进行了小程序开发,现在来对之前的开发体验做一 ...
随机推荐
- RSA 算法-MSDN文档
RSA 算法 若要生成密钥对,可以从创建名为 p 和 q 的两个大的质数开始. 这两个数相乘,结果称为 n. 因为 p 和 q 都是质数,所以 n 的全部因数为 1. p. q 和 n. 如果仅考虑小 ...
- tipask 不能正常解析
<? if(!defined('IN_TIPASK')) exit('Access Denied'); include template('header'); ?> 代码如上,经查询为ph ...
- iOS键盘类型以及样式展示
UIKeyboardTypeDefault: UIKeyboardTypeASCIICapable: UIKeyboardTypeNumbersAndPunctuation: UIKeyboardTy ...
- JDBC的介绍2
一.基础知识 1. 数据持久化 持久化(persistence):对象在内存中创建后,不能永久存在.把对象永久的保存起来就是持久化的过程.而持久化的实现过程大多通过各种关系数据库来完成. 持久化的主要 ...
- Lo4j(一)初识
最近开始在研究log4j,可能因为是想要自己去搭建框架那. 废话不多说,先上一个例子好了. 第一步:当然是引入对象的jar包了 地址:http://www.apache.org/dyn/closer. ...
- laravel 连接mongodb
In this article we will see how to use MongoDB with Laravel (PHP framework). So first we need to ins ...
- ubuntu 14.04 安装中文输入法
记录Ubuntu 14.04 里面安装中文输入法的过程 先安装如下包 sudo apt-get install ibus sudo apt-get install ibus ibus-clutter ...
- QT 5.7.0 交叉编译记录
这一篇记录 Qt 5.x cross-compiler with eglfs , 平台是 TI-AM3354, 上一篇SGX的移植就是为了这一次的交叉编译. 一. 下载QT的源码: 地址: http: ...
- JavaScrip——DOM操作(查找HTML元素/修改元素)
innerHTML 1.查找元素——document.getElementById("intro") 2.输出查找的结果: (1)var a=document.getElement ...
- 网卡phy9161A
硬件1. 网口网口使用4根信号线:两根发送,两根接收.一对信号线中一根承载0——+2.5V信号电压,而另一根负载的电压是0——-2.5V,因此可产生一个5Vpp的信号差.RJ45中有用的就是4根信号线 ...