阅读 1187

微信单页应用的那些事

简介

这里介绍了一次在微信WebView中使用Vue做单页应用的过程中遇到的一些问题,也是比较常见的问题。文末有亮点,希望大家都来~

背景

最近因为快过年了,按照微信以往的尿性,小程序的审核总是有各种条条框框,因此为了让活动在线上正常进行且进行版本的迭代,(主要是为了能得到多一些的开发时间)我们打算采用h5来做活动。

目录

  • 微信小程序跳转WebView的问题;

  • wx.config进行初始化比较优雅的书写方式;

  • 微信签名的一些问题;

  • Vue单页应用在微信浏览器内遇到的一些问题(包含微信支付);

  • 单页应用内的通信;

微信小程序跳转WebView的问题

首先,我们先来聊一聊微信跳转到WebView的一些事情,在此之前大家可以先来看看官方给的文档:web-view · 小程序

普通的跳转没什么好说的,先说说我遇到的问题:

在小程序内进入WebView,我需要把小程序中storage模拟的cookie给带过去,调研了很多资料只得到一个方案,想要从小程序向WebView进行通信的话只能通过拼接URL,那很绝望啊,那个cookie有多长你知道吗😂?

解决方案:

其实也比较简单,我们在小程序进入WebView之前会对cookie进行一次操作,将cookie进行md5得到一个较短的字符串,通过这个md5进行拼接得到较短的URL会减少很多的问题。

注意点:

  • 我们写在URL里边的地址需要encodeURIComponent一下,避免在链接中带有中文字符,否则在 iOS 中打开页面会有白屏的问题。

  • WebView中的openid和小程序中的openid是不一样的,因此各位如果需要做用户关联的话最好用unionid。

  • 跳转的WebView地址需要在mp后台里边进行加白名单,不然无法访问,域名要求是https的。

  • 我们可以通过微信开发者工具里边公众平台进行开发,你可以在里边调试WebView的页面,jssdk的报错也可以在调试工具中体现,最后没有问题再通过代理的方式到手机上过一遍,这里我用的是Charles进行代理的。

wx.config比较优雅的书写方式

项目在引用JS-SDK的API的时候,必须先注入配置信息,也就是wx.config,同一个页面(同一个URL)只需要初始化一次就OK了。wx.config代码如下:

wx.config({
    debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名
    jsApiList: [] // 必填,需要使用的JS接口列表
});
复制代码

具体的信息大家可以看一下文档,这里有一点需要特别提醒大家,写代码的时候,一定要严格按照微信文档里要求去写,大小写,数据类型都要与文档保持一致。微信公众平台

这些都是‘苦口婆心’的话,你要不信,可以试试╮(╯_╰)╭

我在写代码的时候喜欢把不同的功能写在不同的方法里边,初始化的函数只做初始化的事情,这样感觉比较舒服。

  • 在所有微信接口调用前必须保证引入JS-SDK文件,设置JS接口安全域名。

  • JS-SDK里有用户触发时才调用的API,有一点需要注意一下,wx.config是一个客户端的异步操作,在使用方法的时候会存在因异步导致的时机问题,所以方法最好写在wx.ready中,wx.config信息验证成功后会执行wx.ready方法。

  • 我们最好在初始化的时候习惯性的写上wx.errorwx.ready同级,这样之后方法出现问题调试起来也会方便不少,也可以做报错提示。

上边的几个点没问题以后,我来说一下比较优雅的初始化方法,大概逻辑如下:

首先我们需要在方法外边封装一个Promise的模板,但是我的项目中也用了Jquery,我就直接用了里边的$.Deferred()方法

let defer = $.Deferred();
let ready = defer.promise();
复制代码

$.Deferred()其实就是用来返回一个链式实用对象方法来注册多个回调,里边有多个方法

写好这两个方法以后基本上就完成一半了,激不激动!

按照上边介绍的逻辑,ready是初始化成功,那么回调就是resolveerror是初始化失败,回调就是reject。然后我们用defer.promise()去接收两个状态并返回promise对象,之后你就可以愉快的then()了。

注意deferred.promise()也可以接受一个 target 参数,此时传入的 target 将被赋予 Promise 的方法,并作为结果返回,而不是创建一个新对象。


// Existing object
var obj = {
    hello: function( name ) {
      alert( "Hello " + name );
    }
  },
  // Create a Deferred
  defer = $.Deferred();
 
// Set object as a promise
defer.promise( obj );
 
// Resolve the deferred
defer.resolve( "John" );
 
// Use the object as a Promise
obj.done(function( name ) {
  obj.hello( name ); // Will alert "Hello John"
}).hello( "Karl" ); // Will alert "Hello Karl"
复制代码

具体的你可以看看官网的介绍

jQuery API Documentation

这一切都准备完了,接下来我们开始初始化配置


getWxSign(){
	wx.config({
		debug: false, 
		appId: ,
        	timestamp: ,
		nonceStr: ,
		signature: ,
		jsApiList: [],
	});
	wx.error((err) => {
		defer.reject(err);
	});
	wx.ready(() => {
		defer.resolve();
	});
}
复制代码

这两步都完成以后,我们的链式解构就完成了,可以放飞自我的书写。

比如我想要获取微信的收货地址,就可以这么写

ready.then(()=>{
	wx.openAddress({
		success: function (res) {},
		fail: function(err) {},
		cancel: function() {}
	});				
});
复制代码

通过这么一封装,你的代码的可读性就会有一个很大提升,至少看着很舒服(自我感觉)。

当然在使用这些jssdk的API的时候大家要记得加一个🔒,不然会有多次调用的情况,可能会出现返回好几次的情况,当然这个我没有试过,大家可以zuo一下。

微信签名的一些问题

关于微信签名失效的问题,这里主要是想提一下,因为这一块服务端的代码是另外一个小伙伴写的,所以我并没有太多的实践,微信签名服务端最好缓存一下access_token。这样可以避免很多不必要的麻烦。

官方是这么说的:公众平台以access_token为接口调用凭据,来调用接口,所有接口的调用需要先获取access_token,access_token在2小时内有效(7200s),过期需要重新获取,但1天内获取次数有限,开发者需自行存储。

其实在开发之初,服务端的同学还没写完这一块逻辑的时候,前端的同学可以这么去调试,先让服务端获取一次配置信息,然后前端暂时先把这一块写死,这样最少两个小时之内是没问题的,可以提高开发的效率

还有一点,在缓存的有效期内提前去刷新新access_token,这个让服务端的同学统一控制,不要各自刷新,这样会出现冲突的情况,错误体现为invalid signature。确认这类错的时候我们需要充分利用官方给的签名校验工具

微信 JS 接口签名校验工具

如果是因为token过期导致的签名失败,基本上在输入token以后就直接提示了,这个时候就要看看是不是服务端的缓存时间出了问题,当时我们遇到问题的原因是服务端底层关于时间的计算多*60...

当然出现签名错误还有许多的问题,在确保签名算法没有问题的情况下,可能会如下几种情况:

  • 年少不知微信虎,参数大小写没有按照官方要求书写。重点需要注意一下nonceStr,timestamp两个字段。timestamp的数据类型是String,这个也要注意下。

  • 确认URL是页面完整的url。可以通过location.href.split('#')[0]确认,目录的话只要填写都按上一级即可。

假如地址为:
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
那么你的URL可以写到上一级
https://mp.weixin.qq.com/debug/cgi-bin
复制代码
  • config 与获取ticket的AppID不一致。

  • 还有就是服务端如果没有缓存access_token,我们在调试的时候多刷几下可能就会出现问题了,因为开发的时候我感觉刷个几百上千还是很有可能的。

  • 前端传递的URL可能会encodeURIComponent处理过的,服务端需要decode。

  • 还有一个服务端获取的URL与前端的URL不一致,这个在手机上打开以后你可以复制一下链接检查一下。

vue单页应用在微信浏览器内遇到的一些问题

因为这回我们活动用的是vue的单页应用去完成的,路由用vue-router的history模式,因此会遇到一个比较烦躁的问题,具体的问题我描述一下场景:

在iOS上商品详情页跳转到订单详情页面进行支付,支付页面需要调起两个方法,而我的wx.config是mounted的时候就初始化的,所以每次进入这个页面都会报一个invalid signature,我就纳闷了,无意间发现刷新了一下页面就正常了。有时候不报这个签名问题地址也能使用,但是每次支付的时候他就报地址不对

最后我上网查了半天我就发现,history模式下,签名使用的URL是刚进入页面时的URL,为了确认是不是这个问题我把每一页的URL都贴出来,还真是都一样,既然问题确认了,那就好解决了。

解决思路:

在进入页面的时候我们可以先检测一下手机的类型,前边也说了我是在iOS的系统上遇到的问题,在安卓上就没问题,所以无需要对iOS专门处理一下,只要是识别到iOS的机型,那么我就把地址给改了,代码可以参考如下:

// 专门兼容iOS上微信签名的问题
beforeRouteEnter(to, from, next) {
	var isiOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
	if (isiOS && to.path !==  location.pathname) {
		location.assign(to.fullPath)
	} else {
		next();
	}
},
复制代码

当然,解决的办法不止这一个,其实有很多的解决方案,就是感觉其实不太优雅,当时其实我的备用方案就是要么用a标签进行页面跳转,或者进入这个页面以后,你可以reload一下来更新URL。选择怎样的方法大家自己选择吧。

单页应用内的通信

首先我说一下场景大家方便理解一下目的。当时在做项目的时候整个项目只有一块功能用到这通信,当时服务端的童鞋让我不要在表单页面进行提交,因为内容不多,让我把信息带到订单页面结算时一起提交,这个其实就是非父子组件之间的通信,但是这个需要通信的地方没那么多,引入一个vuex感觉太重了,我就直接不考虑这个方案了,就然这个不用,那就直接用eventBus其实也可以,代码如下:

首先我们需要声明一个eventBus的js文件:

import Vue from 'vue';
var eventBus = new Vue({});
export default eventBus; 
复制代码

接下来你需要传递你的值:

import eventBus from 'eventBus/eventBus.js';
let info = {
	a: '',
	b: ''
};
eventBus.$emit('isVal',info);
复制代码

我们在提交表单的页面加一个emit的事件,把填写的内容传出去,接下来我们就要跳回到订单页面了。


import eventBus from 'eventBus/eventBus.js';
eventBus.$on('isVal',(data)=>{
        //....
});
复制代码

使用on进行接收,这样就完成了,其实也是比较简单的逻辑,没涉及到太多东西,对了这个监听可以放在mounted或者create里边,建议用once就OK了。

我们开发的小程序叫做一番市集,欢迎大家注册体验,可以加微信zyf348519452联系我要邀请码哦。

关注下面的标签,发现更多相似文章
评论