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

2023-11-06

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

一、起因

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

二、爬坑之路

2.1、如何复现bug?

要想解决问题,必须要先知道如何复现或是找到引起bug的代码。从上面的截图来看,此处是调用了微信小程序中的wx.downloadFile方法下载用户头像。请求进了fail,一般只有两种情况:

  1. 情况一:请求成功,但是success中的代码异常导致报错,此时会进入fail
  2. 情况二:这个请求异常,直接进入fail

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

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

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

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

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

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

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

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

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

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

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

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

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

2018年的时候,艺灵我也折腾过一翻微信小程序,当时也写了一系列的踩坑文章。于是我进行了搜索,找到了几篇相关文章:

但这些文章中并没有建议使用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三层嵌套模拟项目中的代码.png wx.downloadFile三层嵌套模拟项目中的代码

同样,wx.getImageInfo也是这样调用了三次,在微信小程序中初始界面长这个样子。如图:微信小程序demo界面.png 微信小程序demo界面

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

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

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

// js代码:
/* wx.downloadFile方法下载图片 */
handleDownloadFile() {
  wx.showLoading({
    title: '正在生成海报'
  });
  this.setDisabled(true); /* 设置禁用状态,配合css */
  wx.downloadFile({
    url: this.data.poster.avatar, /* 头像地址 */
    success: (res) => {
      this.setData({
        'tempFilePath.avatar': res.tempFilePath
      });
      wx.downloadFile({
        url: this.data.poster.bg, /* 背景地址 */
        success: (res) => {
          this.setData({
            'tempFilePath.bg': res.tempFilePath
          });
          wx.downloadFile({
            url: this.data.poster.qrCode, /* 二维码 */
            success: (res) => {
              this.setData({
                'tempFilePath.qrCode': res.tempFilePath,
                res: JSON.stringify(res)
              });
              this.draw(); /* 调用封闭的绘图方法 */
            },
            fail: (err) => {
              console.log('qrCode fail=', err); /* 打印二维码的错误信息 */
              const errMsg = this.formatError(err); /* 封闭一个转换err错误信息的函数,方便弹窗中显示 */
              wx.hideLoading(); /* 隐藏loading提示 */
              this.setDisabled(false); /* 清除禁用状态,用户可再次点击 */
              wx.showModal({
                title: '提示',
                content: 'qrCode fail=' + errMsg,
                showCancel: false
              });
            }
          });
        },
        fail: (err) => {
          console.log('bg fail=', err);
          const errMsg = this.formatError(err);
          wx.hideLoading();
          this.setDisabled(false);
          wx.showModal({
            title: '提示',
            content: 'bg fail=' + errMsg,
            showCancel: false
          });
        }
      });
    },
    fail: (err) => {
      console.log('avatar fail=', err);
      const errMsg = this.formatError(err);
      wx.hideLoading();
      this.setDisabled(false);
      wx.showModal({
        title: '提示',
        content: 'avatar fail=' + errMsg,
        showCancel: false
      });
    }
  });
},
/* 设置禁用状态 */
setDisabled(status) {
  this.setData({
    isDisabled: status /* WXML页面中调用样式*/
  });
},
/* 把图片绘到画布上 */
draw() {
  const poster = this.data.tempFilePath;
  const ctx = wx.createCanvasContext('my-canvas', this);
  ctx.width = this.data.canvasWidth;
  ctx.height = this.data.canvasHeight;
  ctx.fillRect(0, 0, this.data.canvasWidth, this.data.canvasHeight);
  ctx.drawImage(poster.bg, 0, 0, this.data.canvasWidth, this.data.canvasHeight);
  ctx.drawImage(poster.avatar, 20, 500, 40, 40);
  ctx.drawImage(poster.qrCode, 140, 350, 100, 100);
  ctx.draw(false, () => {
    this.handleCanvasToTempFilePath();
  });
},
/* 将画布导出成图片 */
handleCanvasToTempFilePath() {
  wx.canvasToTempFilePath({
    canvasId: 'my-canvas',
    width: this.data.canvasWidth,
    height: this.data.canvasHeight,
    success: (res) => {
      wx.previewImage({ /* 预览图片 */
        urls: [res.tempFilePath],
        current: res.tempFilePath
      });
      wx.hideLoading();
      this.setDisabled(false);
    },
    fail: (err) => {
      this.setDisabled(false);
      wx.showModal({
        title: '提示',
        content: '生成商品海报失败',
        showCancel: false,
        success: () => {
          wx.hideLoading();
        }
      });
    }
  }, this); /* 若canvas在组件中,必须带上this! */
},
/* 格式化错误信息 */
formatError(err) {
  let errMsg = err;
  if (typeof err === 'object') {
    errMsg = JSON.stringify(err);
  }
  return errMsg;
}

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

三、验证存储权限

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

四、demo源码

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

源码中会有必要注释和本篇文章的所有示例。若有疑问可与艺灵联系,方式见下方二维码或右侧。

五、其他说明

原文首发于艺灵设计,转载请注明来源,谢谢。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微信小程序从入坑到放弃二十:生成海报前使用wx.downloadFile或wx.getImageInfo时潜在的坑 的相关文章

  • Web测试是在测什么?容易被忽视的小细节总结!

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 CSDN博客 文章浏览阅读2 2k次 点赞85次 收藏11次 你知不知道有这么一个软件测试面试的刷题小程序 里面包含了面试常问的软件测试基础题 web自
  • 微信私密朋友圈被吐槽有BUG

    日前 大量网友在各社交媒体上讨论微信私密朋友圈出现 Bug 的话题 起因是跨年期间一个网友发布了一条 私密朋友圈 但不一会就收到朋友发来的信息 又偷偷发朋友圈了 估计此时网友可能已经 寒毛四起 汗流浃背了 经过和好友沟通得知 好友在刷朋友圈
  • 1-创建小程序项目

    注册 打开https mp weixin qq com 点击 立即注册 选择小程序 获取APPID 登录小程序在 开发管理 gt 开发设置 获取 APPID 开发工具 登录小程序在 开发工具 gt 开发者工具 获取 微信开发者工具 创建小程
  • Typecho 最新XC主题 去除域名授权全解密源码

    简介 Typecho 最新XC主题 去除域名授权全解密源码 这是一款多样式主题 首页支持六种主题样式 支持Pjax优化访问速度 多种单页 如友链 说说等 评论支持表情 自定义编辑器 支持其他样式功能 该主题功能性挺高 比较花里胡哨 感觉有一
  • CMAKE_MAKE_PROGRAM is not set 解读

    目录 CMAKE MAKE PROGRAM 未设置 错误原因 解决方案 示例1 GNU Make 示例2 Ninja CMakeLists txt 的结构 示例 CMakeLists txt 文件 总结 CMAKE MAKE PROGRAM
  • Element-Puls中el-upload组件结合vue-draggable-plus实现上传支持拖拽排序(并保留el-upload原有样式、预览、删除)等功能

    展示效果 需求 需求想要一个可拖拽排序的图片列表 但是发现el upload虽然可以实现照片墙 但是没办法拖拽 实现思路 使用 vue draggable plus 拖拽插件 隐藏Upload原有的已上传文件列表 自定义上传后文件列表的样式
  • 如何给 unplugin-vue-components/vite 写一个简单的 resolver

    大部分工作 unplugin vue components 都已经处理好了 我们只需要接收组件名来判断是否是自己的组件 然后处理对应的导入逻辑 一共 3 个字段 as 重命名类似 import componentNameReName fro
  • 【软件测试】学习笔记-高效提交Bug

    本篇文章介绍如何才能写出一份高效的软件缺陷报告 测试工程师需要利用对需求的理解 高效的执行力以及严密的逻辑推理能力 迅速找出软件中的潜在缺陷 并以缺陷报告的形式递交给开发团队 缺陷报告是测试工程师与开发工程师交流沟通的重要桥梁 也是测试工程
  • 【连续和自适应资源需求估计】通过不断应用在线优化、选择和估计,SARDE能够有效地适应在线跟踪,并使用得到的集成技术减少模型误差(Python代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Python代码 数据 文章
  • 如何创建微信小程序?高效实现你的创意

    在数字化浪潮下 微信小程序以其便捷高效的特点逐渐成为人们日常生活与商业活动的重要载体 有很多人却被难住 若没有没有编程经验 如何创建微信小程序 答案是通过合理利用工具 让创意迅速落地为功能完备的小程序 一 前期准备阶段 1 注册微信公众号平
  • Web 安全漏洞之 OS 命令注入

    什么是 OS 命令注入 上周我们分享了一篇 Web 安全漏洞之 SQL 注入 其原理简单来说就是因为 SQL 是一种结构化字符串语言 攻击者利用可以随意构造语句的漏洞构造了开发者意料之外的语句 而今天要讲的 OS 命令注入其实原理和 SQL
  • 基于java的web仓库管理系统设计与实现

    基于java的web仓库管理系统设计与实现 I 引言 A 研究背景和动机 基于Java的Web仓库管理系统是近年来快速发展的领域之一 它提供了丰富的功能 如数据存储 数据检索 数据分析和数据可视化等 本文将重点介绍基于Java的Web仓库管
  • 软件测试|web自动化测试神器playwright教程(三十八)

    简介 在我们使用selenium时 我们可以获取元素的属性 元素的文本值 以及输入框的内容等 作为比selenium更为强大的web自动化测试神器 playwright也可以实现对元素属性 文本值和输入框内容的抓取 并且实现比seleniu
  • 点击存储到固定时间清除存储

    这段代码 无意间想到的 随便写了下来 运行 根据点击之后传递一个参数 将他存入本地存储 方便测试为10秒 10秒后触发下一个事件 清除本地存储 结束
  • 低代码配置-列表页组件设计

    保存 表单属性存放 bill 筛选项配置存放 filterLayout 列表按钮存放 buttonLayout 列表布局存放 listLayout api存放 api 数据结构 layout 存放表单基础配置 bill 存放按钮基础配置 b
  • 低代码配置-属性配置面板设计

    模块设计 tab项切换 组件基础属性 组件数据属性 组件事件属性 表单属性 模块输出函数设计 tab切换函数 列表表单属性 数据来源 调用接口时一次赋予 无需使用selectItem 如需使用 归入基础属性 列表标题 是否展示筛选区域
  • 考虑光伏出力利用率的电动汽车充电站能量调度策略研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 数据
  • 每天10个前端小知识 <Day 14>

    前端面试基础知识题 1 CSSOM树和DOM树是同时解析的吗 浏览器会下载HTML解析页面生成DOM树 遇到CSS标签就开始解析CSS 这个过程不会阻塞 但是如果遇到了JS脚本 此时假如CSSOM还没有构建完 需要等待CSSOM构建完 再去
  • 【js学习之路】遍历数组api之 `filter `和 `map`的区别

    一 前言 数组是我们在项目中经常使用的数据类型 今天我们主要简述作用于遍历数组的api filter 和 map 的区别 二 filter和map的共同点 首先 我们主要阐述一下 filter 和 map 的共同点 api的参数都是回调函数
  • 深入解析 YAML 配置文件:从语法到最佳实践

    一 认识YAML YAML YAML Ain t Markup Language 是一种人类可读的数据序列化语言 它的设计目标是使数据在不同编程语言之间交换和共享变得简单 YAML采用了一种简洁 直观的语法 以易于阅读和编写的方式表示数据结

随机推荐

  • 开漏输出、推挽输出的区别

    前言 background 测试相关设备引脚输出 使用示波器时发现部分引脚需外接上拉电阻至高电平才能在示波器观察到高阻态 为了深究其中原理 查阅了相关资料 发现知乎中有一篇对这两种输出描述得清晰易懂的文章 此时才真正了解信号高阻态和高电平输
  • SpringBoot--基础--04--拦截器

    SpringBoot 基础 04 拦截器 拦截器 实现HandlerInterceptor接口 注册拦截器 一 代码结构 MyMvcConfig 使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能 Conf
  • 同步方法及同步代码块

    synchronized方法和synchronized块 synchronized方法必须获得对象的锁才能执行 否则线程阻塞 方法一旦执行 就独占此锁 直到方法返回才释放锁 后面被阻塞的线程才能获得这个锁 继续执行 synchronized
  • 谷歌取消了2000多人的offer,特殊时期如何应对裁员?

    就在刚刚 CNBC报道 科技大厂谷歌有上千人饭碗保不住了 图片来自NBC 版权属于原作者 谷歌缩减招聘 据悉这部分人主要是谷歌的合同工和临时工 纽约时报 报道 谷歌取消了2000多人的工作录取 上个月 谷歌首席执行官劈柴君向员工承认 由于新
  • 字符串 字符串中的第一个唯一字符

    LC 字符串中的第一个唯一字符 给定一个字符串 s 找到 它的第一个不重复的字符 并返回它的索引 如果不存在 则返回 1 Swift 实现 func firstUniqChar s String gt Int 创建字符数组 var arra
  • [HTTP] 01一张思维导图带你领略HTTP发展史

    HTTP是什么 HTTP作为一个较常见的应用协议 在面试过程中经常会对其相关内容进行考察 其发展史亦是重点 HTTP是什么 HTTP为Hyper Text Transfer Protocol的简写 中译超文本传输协议 是在计算机网络里面点对
  • 网络原理:ISO/OSI参考模型

    1 ISO OSI参考模型 1 1 各层功能 1 物理层功能 物理层是OSI参考模型的最低层 它利用传输介质为数据链路层提供物理连接 保证二进制位流的透明传送 2 数据链路层 数据链路层是为网络层提供服务的 解决两个相邻结点之间的通信问题
  • C# 学习笔记--个人学习使用 <1>

    C 学习笔记 Chapter 1 C 比较软的基础部分 Section 1 类与命名空间 Part 1 命名空间 NameSpace Part 2 类 Class Section 2 基本元素 Section 3 数据类型 Part 1 什
  • 使用opencv rotate函数实现图片旋转

    使用rotate函数 旋转图片 rotate src dst ROTATE 90 CLOCKWISE 使用rotate 旋转图片 src是源图片的mat dts是目标图片的mat 第3个参数是旋转的角度 有以下4个选项 ROTATE 90
  • android app缓存机制会自动清除,深入理解Android缓存机制(一)缓存简介

    概述 说起缓存 大家可能很容易想到Http的缓存机制 LruCache 其实缓存最初是针对于网络而言的 也是狭义上的缓存 广义的缓存是指对数据的复用 我这里提到的也是广义的缓存 比较常见的是内存缓存以及磁盘缓存 不过要想进一步理解缓存体系
  • Python内置函数详解,进阶必备

    内置函数就是Python给你提供的 拿来直接用的函数 比如print input等 截止到python版本3 6 2 python一共提供了68个内置函数 具体如下 本文将这68个内置函数综合整理为12大类 正在学习Python基础的读者一
  • 关于SDC时钟约束的事

    1 quartus的SDC约束就跟xilinx的ucf约束文件一样 2 主要用途一般是 一从输入端口到寄存器 二寄存器到寄存器 通过设定时钟频率方式进行约束 三寄存器到输出 四创建时钟约束命令 五时钟延迟约束 六时钟抖动约束 七输入和输出延
  • Android实现简单的相册

    用手机浏览靓照也是件非常惬意的事了 然而如何实现这一功能呢 其实也并不难 下面是一个简单的例子 功能为 主屏幕上显示用户选择的靓照 屏幕下面滚动显示靓照集 点击即可浏览 如下图所示 实现代码为 这里图片没法提供了 可以设置自己喜欢的图片 R
  • MYSQL查询优化器

    MYSQL 逻辑结构 MySQL 使用典型的客户端 服务器 Client Server 结构 体系结构大体可以分为三层 客户端 服务器层以及存储引擎层 其中 服务器层又包括了连接管理 查询缓存 SQL 接口 解析器 优化器 缓冲与缓存以及各
  • Navicat连接Mysql遇到的错误

    在navicat链接mysql以后的版本时 会出现2059的错误 这个错误出现的原因是在mysql8之前的版本中加密规则为mysql native password 而在mysql8以后的加密规则为caching sha2 password
  • mysql内测试连通性命令_怎么使用ping命令进行连通性测试

    关于ping命令的作用 ping 命令有助于验证网络层的连通性 一般进行网络故障排除时 可以使用ping 命令向目标计算机或IP地址发送ICMP回显请求 目标计算机会返回回显应答 如果目标计算机不能返回回显应答 说明在源计算机和目标计算机之
  • python提取txt文件中的数据

    从存储在txt文件中的30000多条数据当中提取自己需要的信息 如下图示例的数据格式 需要提取出now后的数值并存储在另外一个txt文件当中 结果示例 code path r r new data1 txt with open path r
  • C++ 项目

    C 方向 10个企业级别项目 138个工作日 1 学生信息管理系统 C 基础 2 俄罗斯方块 控制台 C 基础
  • Arcgis server在solaris和linux上,用直连的方式连接sde的时的配置

    Arcgis server在solaris和linux上 用直连的方式连接sde的时候需要做一点配置才可以连上 1 在
  • 微信小程序从入坑到放弃二十:生成海报前使用wx.downloadFile或wx.getImageInfo时潜在的坑

    摘要 上周六下午16点左右 公司研发群中扔来一张bug截图 当天21点 群里又扔来bug截图 研发团队二话不说开始查找bug如何复现 22点20分左右 我终于复现了bug 随后就是看源码 搜索 跳坑 爬坑 周日同其他研发小伙伴一样 又是奉献