艺灵设计

全部文章
×

微信小程序入坑教程二十:生成海报前使用wx.downloadFile或wx.getImageInfo时潜在的坑

作者:艺灵设计 - 来源:http://www.yilingsj.com - 发布时间:2020-04-05 09:59:27 - 阅: - 评:0 - 积分:0

摘要:上周六下午16点左右,公司研发群中扔来一张bug截图。当天21点,群里又扔来bug截图,研发团队二话不说开始查找bug如何复现。22点20分左右,我终于复现了bug。随后就是看源码、搜索、跳坑、爬坑,周日同其他研发小伙伴一样,又是奉献了一天,那个表单规则功能也被搁置。现在,我该写一篇笔记,记录一下那两天发生的狗血过程了......

一、起因

时间倒退到上周六下午16点23分,产品在公司研发群扔来一张bug截图。如图:周六下午16点多公司群内发来一张bug截图周六下午16点多公司群内发来一张bug截图随即我在项目中进行了搜索,初步定位到了提示信息所在位置。如图:搜索源码找到了提示信息所在位置搜索源码找到了提示信息所在位置此时第一反应就是:this.data.poster.qrCode没值呗,接口返回的锅。然后我就没管这事儿了,继续写那个表单规则去了,但事情并没有结束!当晚21点左右,群里又在提获取头像失败的bug。如图:当晚21点左右群里又在提获取头像失败的bug当晚21点左右群里又在提获取头像失败的bug一搜索提示,又是前端的提示。如图:在源码中搜索获取头像失败并定位代码在源码中搜索获取头像失败并定位代码

二、爬坑之路

2.1、如何复现bug?

要想解决问题,必须要先知道如何复现或是找到引起bug的代码。从上面的截图来看,此处是调用了微信小程序中的wx.downloadFile方法下载用户头像。请求进了fail,一般只有两种情况:
情况一:请求成功,但是success中的代码异常导致报错,此时会进入fail
情况二:这个请求异常,直接进入fail
于是,艺灵我先是看了下success中的代码,乍眼一看并没有发现异常,里面又是两个wx.downloadFile,全部请求成功后才进行画布的操作。然后我把目标锁在了方案二,即:假设此请求不成功的情况。那么此时的url链接是存在问题的。即:originPoster.headimgurl异常。官方文档说仅支持httpsget请求,在微信小程序开发者工具中进行调试发现都符合要求,而且也不报“获取头像失败”的提示!这就难搞了啊,bug无法复现,咋解决问题呢?

这时看了下群里的聊天,发现他小伙伴也说无法复现bug。但是我们老板张总却能复现此bug!!!我不禁一脸懵逼了起来,心想:这都是什么骚操作才会触发了bug???

一晃又是1个小时,此时已经22点多了,还是没有结果。然后我想了想以往的经历,尝试了一下非常规操作,结果bug复现了!!!经过进一步的尝试,已经可以大概率的触发此bug了!激动的我直接在群里截图报喜!如图:当晚22点24分我终于复现了bug当晚22点24分我终于复现了bug

你们是不是想知道我是如何复现的?先卖个关子,后面放答案。下面继续讲述爬坑经历,不想看过程的看官拉到下面看答案。

解决还是有点困难的,毕竟刚才是非常规操作导致bug复现。如果是正常操作,要怎么解决呢?此时已经23点了,一时也没有思路,于是我便洗洗睡觉了。

2.2、另一种骚操作让bug复现,但这是一个误区!

次日再看群消息时发现:@鸿恩大神在昨晚23:30分发消息说百分百复现bug了!如图:昨晚23点30分群消息中说百分百复现bug昨晚23点30分群消息中说百分百复现bug激动的我立马尝试了一下,结果真是百分百复现啊!什么操作呢?安卓手机关闭微信的存储空间即可,此时再点分享百分百弹窗!然后,我就被带到了这个误区里面,一直折腾到下午。最后我自己都感觉到这是个误区了,后来便放弃了这个骚操作。

2.3、scope.writePhotosAlbum保存到相册跟系统存储空间是两个概念!

刚刚说了,@鸿恩大神在群里提到关闭微信的存储空间可以百分百复现bug。于是我就顺着产品的思路:“前端去验证有没有授权”。然后在微信官方文档·小程序中进行了搜索,结果找到了一个接口scope.writePhotosAlbum。官方的描述是:“保存到相册”。然后我就开始摸索这个scope.writePhotosAlbum了,事实证明:我再次掉进坑中!

其实判断这个scope.writePhotosAlbum也挺坑的,只在用户未授权的情况下显示一次,当用户拒绝后,就不再弹窗提醒了。然后我花了很长时间在这个坑上面,当时还在纳闷:怎么一会儿有弹窗一会儿又没弹窗,缓存吗???关于如何正确使用scope.writePhotosAlbum,这里参考一篇文章《微信小程序授权保存到相册功能》,亲测有效!

当我把代码放项目里成功跑起来后,天真的认为bug已经得到了解决!于是,关闭了系统的存储空间进行测试结果发现翻车了!!!弹窗竟然存在!我瞬间凌乱了......

不知过了多久,我再仔细的审题了一下,这才意识到:保存到相册跟系统的存储空间完全是两个概念!然后我果断放弃检测scope.writePhotosAlbum这个方法了。

2.4、查看曾经笔记尝试使用wx.getImageInfo

2018年的时候,艺灵我也折腾过一翻微信小程序,当时也写了一系列的踩坑文章。于是我进行了搜索,找到了几篇相关文章:
微信小程序从入坑到放弃之坑九:canvas合成自定义分享图时wx.getImageInfo的坑
微信小程序从入坑到放弃之坑十:canvas画布缩放的坑
微信小程序从入坑到放弃之坑十一:wx.canvasToTempFilePath的坑
微信小程序实战教程之canvas绘画板+保存图片
但这些文章中并没有建议使用wx.downloadFile来下载图片,然后我觉得这里应该是当时遇到了坑。所以,我把现项目中的wx.downloadFile全换成了wx.getImageInfo进行测试。常规情况下的确没有复现bug,但非常规情况下还是跟wx.downloadFile一样会复现bug。所以,综合考虑了下,先解决非常规操作问题吧!

2.5、非常规操作:频繁点击

好了,到这里也该提示非常规操作的答案了,答案就是:频繁点击!其实,99.9%的项目在正常情况下都扛不住这种骚操作的,如果不用节流防抖等技术进行拦截,出现bug是家常便饭!

2.6、demo复现bug

为了证明不管是使用wx.downloadFile还是使用wx.getImageInfo,在频繁点击的情况下都能复现bug,此处艺灵我特意写了一个简单的demo模拟了一个项目中的场景,大致代码长这个样子。如图:wx.downloadFile三层嵌套模拟项目中的代码.pngwx.downloadFile三层嵌套模拟项目中的代码同样,wx.getImageInfo也是这样调用了三次,在微信小程序中初始界面长这个样子。如图:微信小程序demo界面.png微信小程序demo界面

接下来,在微信开发者工具中点击预览,然后手机扫码访问。待手机进入demo后,快速点击上面两个按钮中的任意一个,此时会看到若干个弹窗downloadFile:fail download fail。为了让看官更直接的理解,艺灵特意录制了一个小视频。视频(点击图片可播放):快速点击按钮复现bug快速点击按钮复现bug(友情提醒:点击上方图片即可播放视频)

2.7、解决方案之一:布尔开关

不管是布尔开关还是加个loading还是css中的pointer-events都可以解决上面视频中存在的问题。像一些表单提交、验证码发送等场景也都可以使用刚刚提到的方法进行拦截。其原理就是:当用户点击时立即设置一个禁用状态,等到要执行的事件处理完成后,再清除禁用状态。这样一来,就能阻止用户的频繁点击操作了。需要注意的是:如果用户直接请求接口,那么刚提到的方法都是拦截不住的。下面来修改下上面的代码,核心代码如下:

  1. /* wx.downloadFile方法下载图片 */
  2. handleDownloadFile() {
  3.   wx.showLoading({
  4.     title: '正在生成海报'
  5.   });
  6.   this.setDisabled(true); /* 设置禁用状态,配合css */
  7.   wx.downloadFile({
  8.     url: this.data.poster.avatar, /* 头像地址 */
  9.     success: (res) => {
  10.       this.setData({
  11.         'tempFilePath.avatar': res.tempFilePath
  12.       });
  13.       wx.downloadFile({
  14.         url: this.data.poster.bg, /* 背景地址 */
  15.         success: (res) => {
  16.           this.setData({
  17.             'tempFilePath.bg': res.tempFilePath
  18.           });
  19.           wx.downloadFile({
  20.             url: this.data.poster.qrCode, /* 二维码 */
  21.             success: (res) => {
  22.               this.setData({
  23.                 'tempFilePath.qrCode': res.tempFilePath,
  24.                 res: JSON.stringify(res)
  25.               });
  26.               this.draw(); /* 调用封闭的绘图方法 */
  27.             },
  28.             fail: (err) => {
  29.               console.log('qrCode fail=', err); /* 打印二维码的错误信息 */
  30.               const errMsg = this.formatError(err); /* 封闭一个转换err错误信息的函数,方便弹窗中显示 */
  31.               wx.hideLoading(); /* 隐藏loading提示 */
  32.               this.setDisabled(false); /* 清除禁用状态,用户可再次点击 */
  33.               wx.showModal({
  34.                 title: '提示',
  35.                 content: 'qrCode fail=' + errMsg,
  36.                 showCancel: false
  37.               });
  38.             }
  39.           });
  40.         },
  41.         fail: (err) => {
  42.           console.log('bg fail=', err);
  43.           const errMsg = this.formatError(err);
  44.           wx.hideLoading();
  45.           this.setDisabled(false);
  46.           wx.showModal({
  47.             title: '提示',
  48.             content: 'bg fail=' + errMsg,
  49.             showCancel: false
  50.           });
  51.         }
  52.       });
  53.     },
  54.     fail: (err) => {
  55.       console.log('avatar fail=', err);
  56.       const errMsg = this.formatError(err);
  57.       wx.hideLoading();
  58.       this.setDisabled(false);
  59.       wx.showModal({
  60.         title: '提示',
  61.         content: 'avatar fail=' + errMsg,
  62.         showCancel: false
  63.       });
  64.     }
  65.   });
  66. },
  67. /* 设置禁用状态 */
  68. setDisabled(status) {
  69.   this.setData({
  70.     isDisabled: status /* WXML页面中调用样式*/
  71.   });
  72. },
  73. /* 把图片绘到画布上 */
  74. draw() {
  75.   const poster = this.data.tempFilePath;
  76.   const ctx = wx.createCanvasContext('my-canvas', this);
  77.   ctx.width = this.data.canvasWidth;
  78.   ctx.height = this.data.canvasHeight;
  79.   ctx.fillRect(0, 0, this.data.canvasWidth, this.data.canvasHeight);
  80.   ctx.drawImage(poster.bg, 0, 0, this.data.canvasWidth, this.data.canvasHeight);
  81.   ctx.drawImage(poster.avatar, 20, 500, 40, 40);
  82.   ctx.drawImage(poster.qrCode, 140, 350, 100, 100);
  83.   ctx.draw(false, () => {
  84.     this.handleCanvasToTempFilePath();
  85.   });
  86. },
  87. /* 将画布导出成图片 */
  88. handleCanvasToTempFilePath() {
  89.   wx.canvasToTempFilePath({
  90.     canvasId: 'my-canvas',
  91.     width: this.data.canvasWidth,
  92.     height: this.data.canvasHeight,
  93.     success: (res) => {
  94.       wx.previewImage({ /* 预览图片 */
  95.         urls: [res.tempFilePath],
  96.         current: res.tempFilePath
  97.       });
  98.       wx.hideLoading();
  99.       this.setDisabled(false);
  100.     },
  101.     fail: (err) => {
  102.       this.setDisabled(false);
  103.       wx.showModal({
  104.         title: '提示',
  105.         content: '生成商品海报失败',
  106.         showCancel: false,
  107.         success: () => {
  108.           wx.hideLoading();
  109.         }
  110.       });
  111.     }
  112.   }, this); /* 若canvas在组件中,必须带上this! */
  113. },
  114. /* 格式化错误信息 */
  115. formatError(err) {
  116.   let errMsg = err;
  117.   if (typeof err === 'object') {
  118.     errMsg = JSON.stringify(err);
  119.   }
  120.   return errMsg;
  121. }

保存上面的代码并运行,再也不怕用户频繁点击了。哈哈哈!但是,如果再出现弹窗失败的错误,那我就真不知道到底是不是接口返回的问题了。。。。。。

三、验证存储权限

当安卓用户关闭了微信的存储权限后再点击按钮时会进入fail,弹窗提示为:downloadFile:fail download fail:1001。所以,我们可以对上面的代码进行补充。不过这种情况应该很少发生,毕竟禁用存储空间权限后,使用微信聊天时是连图片都发不了的。如图:安卓用户关闭微信存储空间权限后无法使用图片功能安卓用户关闭微信存储空间权限后无法使用图片功能

四、demo源码

demo源码已上传到了github上,如果看官需要研究源码,可以点击下面的链接进行访问并下载。

  1. 网址: https://github.com/yilingsj/weixinxiaochengxu/tree/dev-downloadFile-20200404

五、最后

写代码时遇到有请求的地方,为了保险起见最好加以拦截,避免用户频繁操作。本篇文章到此结束,下一篇再来详细介绍下scope.writePhotosAlbum 的使用场景。

转载声明:
  若亲想转载本文到其它平台,请务必保留本文出处!
本文链接:/xwzj/2020-04-05/weixin-downloadFile-getImageInfo.html

若亲不想直保留地址,含蓄保留也行。艺灵不想再看到有人拿我的技术文章到他的地盘或者是其它平台做教(装)程(B)而不留下我的痕迹。文章你可以随便转载,随便修改,但请尊重艺灵的劳动成果!谢谢理解。

亲,扫个码支持一下艺灵呗~
如果您觉得本文的内容对您有所帮助,您可以用支付宝打赏下艺灵哦!

Tag: 微信小程序 小程序工具 小程序教程 分享海报 wx.downloadFile wx.getImageInfo scope.writePhotosAlbum wx

上一篇: 万城景湖园-关注公众号码上有钱   下一篇: 微信小程序入坑教程二十一:使用wx.saveImageToPhotosAlbum保存图片时通过检测scope.writePhotosAlbum权限来提醒用户是否需要授权

评论区