vue中使用微信公众号js-sdk踩坑记录(2)

最近又在vue中捣鼓了下微信公众号api的接入,不得不说这里边水是真的深啊,上次分享了微信受权登陆和js-sdk签名的部分,其中不少朋友私信我表示了疑惑,今天我就再次尝试理顺一下这里边的坑吧:php

微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。
经过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时能够直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

分享页面到朋友圈

上文是从官方文档中摘出来的,因而可知,咱们若是要实如今公众号的内嵌h5中实现微信分享,支付等功能,就得引入js-sdk。
使用js-sdk有一个关键的环节,那就是经过config接口注入权限验证配置,而配置中有个signature参数是须要借助服务端获取的,这里就不过多探讨了,你们经过官方文档能够深刻了解。vue

Hash or History?

上篇文章,我推荐你们在vue中配置vue-router使用hash模式,那么hash模式和history模式到底有什么差异呢?我举个栗子,假设咱们都经过http://domain.com进入,而后跳转到路由为/jssdk的页面须要用到jssdk,那么实际js-sdk进行签名校验时所获取的当前页面url在ios和andrioid是不一样的,这里我经过表格展现出来:
android

真相都在表格里,我表达能力很差恕我偷个懒23333333。ios

若是阁下没有接入分享指定页面的需求的话,hash模式很方便,可是无奈笔者须要接微信分享,若是使用hash模式,分享出去的地址,微信会自动处理掉#后边的部分,那么我就无法分享指定页面到朋友圈或者给朋友了。
怎么办呢,只能硬着脑子解决history问题咯,其实也好解决,就是iOS须要使用第一次进入页面的URL获取签名,安卓每次路由切换都从新配置签名。我这里罗列两个方案:web

1.入口文件中记录页面URL,在页面组件建立完成后,ios获取记录的url进行签名,android获取当前路由(window.location.href.split('#')[0]),请移步个人上一篇博客vue-router

2.入口文件中直接进行签名和注入配置,仅针对android在每次切换路由时再从新签名和配置。该方案适合全部页面都须要用到js-sdk的状况axios

问题记录

现列出我在捣鼓过程当中遇到的一个个bug:segmentfault

1.安卓设备能分享ios设备不能分享;
出现该问题的缘由就是由于采用了history模式,且没有考虑到ios校验签名获取的url是第一次访问的url而使用了切换后的url。api

2.ios设备进入页面时不能分享,手动刷新页面后才能分享;
屡次测试后我发现,测试分享的时候,若是是访问的连接没带http://的话,除了首页其余页面都是失效的,测试时落地页ur必需要加http://安全

3.点击连接能正常分享,点击别人分享的图文消息以后不能分享;
猜测1:点击图文消息时候,微信进行签名校验的url去掉了本身添加的参数,因此咱们在进行签名时也要去掉微信添加的参数? 因此我把微信参数即
`?from=singlemessage&isappinstalled=0'这个部分去掉,结果依旧是分享失败,而我本身随意加一个参数,分享则正常,我随意加两个参数的时候,分享却又不正常了。

猜测2: 微信分享进行签名校验的url仅能容许一个参数?因此我这样写:
url = location.href.split('&')[0],验证后发现是错误的,再仔细一想我竟然有这么可怕的想法,连官方文档都不相信了。

猜测3:url难道须要进行编码?即
url = encodeURIComponent(window.location.href.split('#')[0])经我屡次debug,终于找到问题,就是须要对签名的url进行编码,word哥,不容易啊

仅须要对签名的url进行编码,分享配置中的url不须要编码
仅须要对签名的url进行编码,分享配置中的url不须要编码
仅须要对签名的url进行编码,分享配置中的url不须要编码

这里又是一个坑,务必当心。

常常N次的debug和尝试以后我码了几十行代码,解决了以上全部问题,回首一看我真的是年轻啊,也就那么简单的逻辑,也许换我的一步就到位了,我却和各类各样的bug战斗了n多遍(改动一点代码就要上生产环境debug的心酸有谁能懂),唉。。。

Coding

分享一下我怎么按照第二种方案进行微信分享配置的
因为我项目中需求是基本全部页面都须要能分享,因此在每一个page组件中去获取签名是不实际的,因此我就想借助vue-router的after钩子去完成分享配置的操做,对于android则还须要从新进行签名。

// main.js
...
import wx from 'weixin-js-sdk'
import request from 'axios'
...
router.afterEach((to, from) => {
  let _url = window.location.origin + to.fullPath
  // 非ios设备,切换路由时候进行从新签名
  if (window.__wxjs_is_wkwebview !== true) {
    request.get('/api/jssdk?url=' + encodeURIComponent(_url)).then(function (_lists) {
      // 注入配置
      wx.config({
      ...
      })
    })
  }
  // 微信分享配置
  wx.ready(function () {
    wx.onMenuShareTimeline({
     ...
    })
    wx.onMenuShareAppMessage({
      ...
    })
  })
})

...
// ios 设备进入页面则进行js-sdk签名
if (window.__wxjs_is_wkwebview === true) {
  let _url = window.location.href.split('#')[0]
  request.get('/api/jssdk?url=' + encodeURIComponent(_url)).then(function (res) {
    let _lists = res
    wx.config({
      debug: false,
      appId: _lists.appId,
      timestamp: _lists.timestamp,
      nonceStr: _lists.nonceStr,
      signature: _lists.signature,
      jsApiList: ['chooseImage', 'uploadImage', 'previewImage', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareTimeline', 'chooseWXPay']
    })
  })
}

总结: 总之简要归纳就是要想分享成功,必须签名是成功的,要想签名成功,必须保证调用签名配置的时候微信校验签名获取的url(ios永远是第一次进入页面的url)和咱们请求服务端获取签名时提交的url一致。

调用微信支付

两个方案何去何从

h5使用微信支付,细心的人会发现,微信是有两个方案的,我大体了解了一个,一个是js-sdk中开放的能力,一个是微信支付开放平台提供的接口

js-sdk版本:

微信支付版本:

若是你只须要在公众号中调用支付,两个方法均可以,笔者因为已经使用js-sdk接入了其余功能,因此这里就选择了chooseWXPay方式。

接入步骤

在其余功能都接入成功的前提下,接支付就很快很方便了,笔者把主要步骤列下:

  1. 微信公众平台中配置好js安全接口域名(例如www.imwty.com),这个是调用js-sdk的前提,公众号支付也是基于js-sdk;
  2. 微信支付平台中设置支付目录,参见微信支付开发文档,这里要说明的是,你须要进行支付的页面路由是什么,就要配置什么,并且须要在后边加上/(例如www.imwty.com/pay/)
  3. 调用js-sdk签名配置(wechat.config),上文已有说起。
  4. 在点击支付按钮的逻辑中,调用wechat.chooseWXPay()方法,该方法也涉及到支付签名,须要从服务端去获取签名信息

注意的点:访问支付页面务必不要遗漏/,微信那边会严格比较调用第4步骤时你所在的页面路由和支付平台中设置的路由是否一致。

Coding

这里主要展现第4步骤中笔者的写法,仅供参考

...
methods () {
 handlerPay () {**粗体文本**
    let self = this
    // 进行支付签名
    apiUtil.get('/api/jssdk/pay', {amount: this.amount}).then(function (wxmsg) {
      self.$wechat.chooseWXPay({
     // 支付签名时间戳,注意微信jssdk中的全部使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
          appId: wxmsg.appId,
          timestamp: wxmsg.timeStamp,
          nonceStr: wxmsg.nonceStr, // 支付签名随机串,不长于 32 位
          package: wxmsg.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
          signType: wxmsg.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
          paySign: wxmsg.paySign, // 支付签名
          success: function (res) {
            // 支付成功的回调函数
          },
          cancel: function (res) {
            // 支付取消的回调函数
          },
          error: function (res) {
            // 支付失败的回调函数
          }
    }).catch(function () {
      ...
    })
  }
}

结语

因为本人文笔通常,思惟的表达估计不到位,看法也是浅尝辄止,因此若是看官您有疑惑的地方或者有歧义欢迎来和本人交流。为了方便你们互相沟通,本人也建立了一个vue公众号开发的qq群,欢迎加入和你们一块儿分享开发心得,qq群号:130903919

相关文章
相关标签/搜索