【问题记录】微信公众号踩坑

记录在微信公众号开发过程中遇到的一些问题以及解决方法

一、开发环境

  • Vue 2.5.2
  • weixin-js-sdk 1.4.0-test

二、问题与解决方法

1. 微信接口报错63002:invalid signature,即签名错误

1.1 问题分析

微信提供了专门的签名算法用于生成签名,一般由后端调用微信的接口生成签名,签名错误的原因一般有两大类:一是传入签名算法的参数错误;二是传入wx.config(微信提供的用于注入权限验证配置的接口)接口的参数错误。

1.2 解决方法
1.2.1 排查是否是传入签名算法的参数错误

1)参数一:noncestr(随机字符串);

2)参数二:有效的jsapi_ticket,这个参数微信也提供了专门的接口生成,正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,因此必须在自己的服务全局缓存jsapi_ticket

3)参数三:timestamp(时间戳),一定要确保服务器的时间是正确的,不然生成出来的签名是无效的;

4)参数四:当前网页的url,一定要注意传入接口的url不包含#及其后面部分,且必须是动态获取的

1.2.2 排查是否是传入wx.config接口的参数错误

1)参数一:appId(公众号的唯一标识),确保传入的appId是当前微信公众号的appId,在开发过程中,会经常弄混淆;

2)参数二:timestamp(生成签名的时间戳),一般直接由后端接口返回,确保与传入签名算法中的timestamp一致

3)参数三:nonceStr(生成签名的随机串),一般直接由后端接口返回,注意这个字段是驼峰式的,不要写错,与传入签名算法中的字段名称大小写有区分;

4)参数四:signature(签名),后端生成的签名,确保签名正确,可以使用微信提供的页面工具来校验

1.2.3 其他可能引起错误的原因

1)确保JS接口安全域名配置正确,JS接口安全域名不需要添加http(s)://,直接放域名或者ip地址;

2)确保网页账号与JS接口安全域名一样


2. 多图片上传时调用wx.getLocalImgData报错script error

2.1 背景

在项目中使用微信的接口完成上传图片的功能,大致的实现流程如下:

  • 调用wx.chooseImage拍照或者从手机相册选择图片,该接口会返回选定照片的本地ID列表localIds,安卓可以使用localId作为img标签的src属性显示图片,但是IOS无法显示,因此不建议直接使用localId来显示图片;
  • 使用wx.getLocalImgData将选定的照片转换为base64数据,由于图片允许多选,因此需要多次调用该接口;
  • 调用项目接口,将base64数据上传到服务器中,利用接口返回的图片在服务器上的地址,来回显图片。
2.2 存在的问题
  • 问题一:wx.getLocalImgData接口单次调用成功,循环调用报错script error;
  • 问题二:利用本地接口将wx.getLocalImgData生成的base64上传至服务器并返回图片在服务器的地址,从而回显图片,安卓可以成功回显,但是IOS上不能。

代码如下:

    // 选择图片
    chooseImage() {
      let that = this
      wx.chooseImage({
        count: that.imgMaxNum, // 允许上传的图片个数
        sizeType: ['original', 'compressed'],
        sourceType: ['album', 'camera'],
        success: function (res) {
          // localIds是一个数组
          const localIds = res.localIds;
          // 循环数组,将每个图片都转换为base64
          localIds.forEach(localId => {
            that.changeImgToBase64(localId);
          });
        }
      });
    },
    // 将图片转换为base64
    changeImgToBase64(localId) {
      let that = this;
      wx.getLocalImgData({
        localId: localId,
        success: function (res) {
          // localData是图片的base64数据
          let localData = res.localData;
          // 将base64上传到服务器
          that.uploadImage(localData);
        }
      });
    },
    // 将图片上传到服务器
    uploadImage(base64Data) {
       // 其余代码省略
       // photos保存的是图片在服务器上的地址
       this.photos.push(path);
    }
2.3 问题分析
  • 猜测:类似于这种文件的读写操作,应该是串行的,各个任务按顺序执行,完成一个之后才能进行下一个。循环调用wx.getLocalImgData,类似于在循环里添加了一个异步请求,因此可以通过在回调函数中递归wx.getLocalImgData来达到同步执行。

  • wx.getLocalImgData接口可以将图片转换为base64,但是转换后的base64在安卓和IOS上返回的是不一样的,
    IOS中返回的base64会加上"data:image/jpg;base64,"头部,而安卓不会,我所在的项目后端提供的接口的入参不需要这个头部,因此IOS需要将头部截取掉。

2.4 解决方法
    // 选择图片
    chooseImage() {
      let that = this
      wx.chooseImage({
        count: that.imgMaxNum, // 允许上传的图片个数
        sizeType: ['original', 'compressed'],
        sourceType: ['album', 'camera'],
        success: function (res) {
          // 将返回的localIds全局保存
          that.localIds = res.localIds
          that.changeImgToBase64(that.localIds.shift());
        }
      });
    },
    // 将图片转换为base64
    changeImgToBase64(localId) {
      let that = this;
      wx.getLocalImgData({
        localId: localId,
        success: function (res) {
          let localData = res.localData;
          const base = 'data:image/jpg;base64,';
          
          // IOS下截取头部
          if (localData.indexOf(base) === 0) {
            localData = localData.substring(base.length, localData.length);
          }
          that.uploadImage(localData);
          
          // 递归调用
          if (that.localIds.length > 0) {
            that.changeImgToBase64(that.localIds.shift());
          }
        }
      });
    },
    // 将图片上传到服务器
    uploadImage(base64Data) {
       // 其余代码省略
       // photos保存的是图片在服务器上的地址
       this.photos.push(path);
    }

3. SPA项目:从微信菜单跳转到子页面时,页面无法正确跳转到子页面,而是跳转到首页

3.1 问题分析

Vue Router默认使用hash模式,因此URL是这样的:http://yoursite.com/#/hello。由于签名算法中的url参数的值不包含#及其后面部分,因此在获取url的时候使用了location.href.split("#")[0],猜测微信的菜单跳转也是一样的,因此每次跳转都只能跳转到首页。

3.2 解决方法
3.2.1 修改Vue Router为history模式

使用history模式后,链接中不再包含#,而是变成了http://yoursite.com/hello

但是使用这种方法,build后页面变成了空白的,看了官方文档后才知道history模式需要后台配置支持,由于之前没有用过这种模式,所以需要花更多的时间去调研,时间成本较大,因此就没有考虑这个方案了。

3.2.2 将链接中的#编码

这个方法比较巧妙,既然#以及#后面的内容会被忽略,那就把#编码一下,链接中没有直接出现#,而且浏览器也能解析。

解析后的地址为:http://yoursite.com%2F%23%2Fhello




猜你喜欢

转载自www.cnblogs.com/jiafifteen/p/12214714.html