记一次 H5 分享图片保存到本地的抓狂经历

2,197 阅读6分钟

项目需求

需要在2天之内搞定分享功能,包括分享链接以及分享图片,主要说分享图片遇到的坑😂

  • 用户点击分享图片,生成一个全屏分享图
  • 用户点击保存,图片保存到本地

无法保存到本地

巨坑1 -- 保存图片到本地,行不通

尝试说服产品经理砍掉这个需求

尝试了网上N多种方案,都不行,只好尝试最后一种方案

说服产品经理,砍掉这个需求

产品经理提出建议,人家都能做,你为什么不能?

  1. 查看产品经理给出的网址,分析源码,发现真相
  2. 人家根本就没做,只是长按能触发浏览器自带的保存图片功能
  3. 瞬间悟了,原来还能这么搞...

方案变种,生成图片,让用户长按图片进行保存

  • 确定生成图片方案,调研 DOM 生成图片的第三方仓库,快速完成需求
  • 经过使用复杂度,以及项目 ISSUE 对比, 决定使用dom-to-image 进行保存。

生成图片模糊

小坑1 -- 生成的图片有点模糊

**我拿着手机进行测试,这图片怎么这么模糊**

推测可能的原因🤔️

  1. 是不是图片的质量没有开到最高?
  2. 是不是生成图片的格式问题?
  3. 生成图片的宽高比较小?
  4. 这个组件库不能生成高清图片?

经过一一测试跟比对,全部否决

那是啥问题?(此时表情已渐渐抓狂😫)

解决方案

将图片缩放3倍,配置如下

const scale = 3;
const style = {
  transform: 'scale(' + scale + ')',
  transformOrigin: `10px 0`,
  width: width + 'px',
  height: height + 'px',
};
const param = {
  height: height * scale,
  width: width * scale,
  quality: 1,
  style,
};

dom-to-image 兼容性不太好

大坑2 -- `svg foreignObject` 兼容性不太好,部分浏览器生成不了图片

* 用`UC`浏览器进行测试,无问题 * 用`微信`浏览器进行测试,无问题 * 用`QQ`浏览器进行测试,`Error: XXX` * 报错了,用`IOS`手机再试试其它的浏览器,也提示 `Error: XXX`

果然,事情不是那么顺利就能解决的

查看官方文档以及搜索ISSUE发现,项目中赫然写着不兼容Safari 以及 IE浏览器

当时自己为啥要选择使用这个仓库???🤔️

经过再次对比,决定使用 html2canvas 这个仓库,先让 html 生成 canvas 再生成图片

没问题了,嘿嘿😁

html2canvas 部分属性样式无法还原

小坑3 -- `html2canvas` 部分属性样式无法还原,图片生成有白边

* 这确实没办法了,要么不用不支持的样式,要么用其它方式实现类似的`css`效果 * 天生受限,绘制出的图片还原度不是很高,**暂时解决不了**

图片生成有白边,排查了下,是因为滚动造成定位不准造成的

产品坚持想要border-image的效果,只好用其它支持的样式来模拟了

  1. 叠一个divbackground: linear-gradient() 属性模拟 border-image

还原度不太好的问题,还是无法解决,无奈只有采用这种方案

  1. 使用 dom-to-image 支持大部分浏览器,html2canvas 生成的图片只能将就将就了,毕竟时间催得紧

经过一顿操作之后,终于没问题了,测试接手,上线到预发环境

图片请求缓存,跨域

巨坑2 -- 生成出来的图片里面,有些图片元素没有绘制出来

* 打开控制台,发现请求图片,有跨域报错 * 瞬间定位问题,发现线上走的静态资源的地址是不同域名,而测试环境用的是一个域名,所以可能会有跨域的问题🤔 * 自信的打开控制台, 查看`Response Headers`, 发现允许跨域的请求头没有返回 * 马上找到运维同学,询问为何没配置,跨域相关的请求头,然后被打脸了...

我:为啥这个域名的跨域请求头没配置?

运维:不可能,我配置了,咋个没有嘛!

我:你看看,没有返回啊,你确定配置了吗?

运维:你用 curl https://xxxx 试一下,看看返回没有嘛

我:我还不信了,马上试试... 真的返回了,卧槽😂

那这个到底是咋回事!!!(表情已经狰狞了😫)


强迫自己沉着冷静的思考了一番

运维配置了跨域允许,但是请求没有返回,然后预览图还可以出来。

只是生成截图的时候,图片跨域了,然后... 一团乱麻

因为必须要上线,短短的时间之内,心态还是没稳住,冷静不下来

求助一下其他小伙伴吧

求助了几个小伙伴,得到的答案都类似

小伙伴1. 这个我做过类似的,我们那个域名没问题。

小伙伴2. 是缓存的问题吗?(🐂🍺)

查看小伙伴1他们的域名,发现配置的头是 Access-Control-Allow-Origin: *

然后让运维尝试一下,顺利解决该问题😊

过了两天之后,运维:这个配置可能有安全问题,有没有其它解决方案?

  • 先是询问了运维,为啥没正常返回这个 Access-Control-Allow-Origin: https://xxx 响应头
  • 运维给出了一个答案:‘我也不太清楚,咱们用的 AWS 的服务,是统一配置的 CDN 缓存策略以及响应头,我配了,只是你走的是缓存,所以没有。’
  • 运维:我勾选了Disable cache,就可以正常生成,就是浏览器的缓存问题,你们想办法解决!

行吧,目前的配置策略下,好歹知道了是因为缓存引发的问题

经过不断的尝试,查看第三方组件源码,摸索(询问其它小伙伴)的方式,终于确定了问题的原因

  • 图片自身的请求,不会涉及到跨域问题,所以预览图能正常呈现
  • 第三方组件生成图片时,会使用 xhr 请求图片的地址,由于跨域配置没有返回以及配置的缓存策略,让这一次xhr的请求,走的是缓存逻辑,之前的请求没有返回响应头,所以这一次也没有

dom-to-image 有一个选项 cacheBust

  • 开启这个选项之后,请求图片的时,会增加一个时间戳,让这次的请求不走缓存逻辑

html2canvas 没有提供类似的功能,只能改动源代码了...


加上随机数请求

小坑4 -- `Base64`加上随机数报错

干,没想到还有这一茬,改动源码,写上正则匹配,只增加http:// | https:// 开头的请求

终于解决了问题...

尾记

又过了两天之后,运维:解决了,配置有问题,你看看跨域头能返回了吗? 🐂🍺