问题:
在安卓、微信开发者工具、苹果的单页面点开始,微信js初始化正常,在苹果A页面跳转到B页面时初始化时出现失败

问题原因:

从A页面跳转到B页面时,由于是使用vue-router切换,都是操作浏览器历史记录,所以ios端微信浏览器锁定的url的还是A页面的url。

这个时候,是不是很多人都会认为,既然页面路由变化了,那我重新请求下url签名接口,不就可以了。呵呵呵,你会发现报错:invalid signature。但是再刷新一下,又没有签名问题,这是什么原因呢???

那么你在请求url签名接口的时候,传递的url参数又是什么呢?大概如下吧:
url1、直接是 location.href (history模式)
url2、自己拼装的 location.origin + ‘/#’ + this.$route.pullPath (hash模式)
这个时候,你请求的接口都没问题,也能拿到签名数据。但是

问题就出在:你所请求的url签名地址和浏览器执行jweixin-1.x.x.js时锁定的地址 不一致、不一致、不一致。你当前请求的可能是url1或url2,而此时微信锁定的地址仍然是进入A页面时的url(因为在进入A页面是加载并执行了jweixin-1.x.x.js, 而路由变化A到B时,并没有再次执行jxinwei-1.x.x.js)。所以问题就发生了,但是你再刷新一下,jweixin-1.x.x.js重新执行,此时微信浏览器锁定的url就是你当前刷新的url地址了,所以签名又成功了。
主要是因为:
【IOS】:ios微信端,路由变化时,微信认为SPA的url是不变的。
【Android】:android微信端,路由变化时,SPA的url是会变的(官方在安卓6.2版本,才对SPA变化作了支持)

所以,发起签名的url必须是微信锁定的url。

解决方案A:
IOS端,把请求签名的url,保存到全局变量中。路由切换后,在调用分享接口时,使用全局变量里保存的url来请求签名

// 记录进入app时的url
if (typeof window.entryUrl === 'undefined' || window.entryUrl === '') {
    window.entryUrl = location.href.split('#')[0]
}
// 进行签名的时候  Android 不用使用之前的链接, ios 需要
let signLink =  /(Android)/i.test(navigator.userAgent) ? location.href.split('#')[0] : window.entryUrl;

解决方案B 在若依前后端分离vue:3.4.0版本中解决方法

在permission.js中的router.beforeEach方法中添加下列代码,根据自己的实际业务的实际位置来添加。我这块业务不需要鉴权,直接就放在白名单下面了
// 如果是ios初次进入直接初始化微信JS
if (isIOS()) {
        if (from.path === '/') {
          requestWxStr().then(r => {
            console.log('ios初始化完成')
          })
        }
      }
这是参考代码
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
import { isIOS, requestWxStr } from '@/main'

NProgress.configure({ showSpinner: false })

//路由白名单列表,把路由添加到这个数组,不用登陆也可以访问
const whiteList = ['/login', '/auth-redirect', '/bind', '/register', '/404']

router.beforeEach((to, from, next) => {
  // console.log("form---permission"+form.path)
  // 请求路由时进度条开始
  NProgress.start()
  //如果存在token,即存在已登陆的令牌
  if (getToken()) {
    /* has token*/
    //如果用户存在令牌的情况请求登录页面,就让用户直接跳转到首页,避免存在重复登录的情况
    if (to.path === '/login' || to.path === '/wx_login') {
      // 直接跳转到首页,当然取决于你的路由重定向到哪里
      next({ path: '/' })
      //一定要关闭进度条
      NProgress.done()
    } else {
      //如果已经有令牌的用户请求的不是登录页,是其他页面
      //就从Vuex里拿到用户的信息,这里也证明用户不是第一次登录了
      if (store.getters.roles.length === 0) {
        // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(res => {
          // 拉取user_info
          const roles = res.roles
          store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => {
            // 根据roles权限生成可访问的路由表
            router.addRoutes(accessRoutes) // 动态添加可访问路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
          })
        }).catch(err => {
          store.dispatch('LogOut').then(() => {
            Message.error(err)
            next({ path: '/' })
          })
        })
      } else {
        next()
      }
    }
  } else {
    console.log('to.path=>', to.path)
    // 没有token
    if (whiteList.indexOf(to.path) !== -1) {
      // 在免登录白名单,直接进入

      if (isIOS()) {
        if (from.path === '/') {
          requestWxStr().then(r => {
            console.log('ios初始化完成')
          })
        }
      }

      next()
    } else {
      next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  NProgress.done()
})

在main.js中写这两个方法,在其他地方写也可以


//提取出来的公共方法
/*
* 判断是否IOS环境
* */
export function isIOS () {
  let isIphone = navigator.userAgent.includes('iPhone')
  let isIpad = navigator.userAgent.includes('iPad')
  return isIphone || isIpad
}

/*
* 获取微信签名,注入权限验证配置
* */
export async function requestWxStr () {
  let url = location.href.split('#')[0]
  getSign(url).then((res) => {
    let jsonData = res
    wx.config({
      // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
      debug: true,
      // 必填,公众号的唯一标识
      appId: jsonData.appId,
      // 必填,生成签名的时间戳
      timestamp: '' + jsonData.timestamp,
      // 必填,生成签名的随机串
      nonceStr: jsonData.nonceStr,
      // 必填,签名
      signature: jsonData.signature,
      // 必填,需要使用的JS接口列表,所有JS接口列表:获取登录信息
      jsApiList: ['checkJsApi', 'getLocation']
    })
  })
}
在需要使用微信js的页面
created() {
// 如果不是IOS在这里开始初始化
    if(!isIOS()){
      requestWxStr()
    }
  }

通过以上修改,在Android和ios环境下都可以正常调用jssdk了。应该是ios的微信对pushState的H5新特性没有很好地兼容造成的。在vue的mode: 'history’模式,或者react使用browserHistory会出现这种情况。最坑爹的是官方文档并没有任何相关说明。

在微信电脑端打开网页时wx.getLocation提示function not implement;这个问题在官方没有找到明确答复,可以持续关注
pc初始化问题:https://developers.weixin.qq.com/community/develop/doc/00086c34298e180834b96f52456800
spa单页面解释:https://blog.csdn.net/huangpb123/article/details/86183453
参考链接和其他解决方案:
https://blog.csdn.net/hualvm/article/details/85344076
https://www.jianshu.com/p/12a9e244cfa4
https://www.cnblogs.com/tengrl/p/10429278.html
https://www.cnblogs.com/xueshanshan/p/8692092.html
https://github.com/vuejs/vue-router/issues/481

Logo

快速构建 Web 应用程序

更多推荐