问题
一个旅行社的客户反馈,从他们微信公众号复制之前的文章,粘贴到微信小程序的后台富文本编辑器 (summernote) 之后,点击保存出错。
从 laravel 日志看,是报了超出字段长度。从以往的经验看,如果使用了 base64 的图片才会有此问题。否则很难超过 text 类型 (TEXT 能存储 6.5 万个字符)
同事测试的时候,发现
- 如果图片未加载完,复制到 summernote 里的就是 base64 图片
- 如果图片加载完,复制到 summernote 里的就是图片的 URL 地址
这有点不合逻辑了。
排查
今天,我看看了微信公众号文章的网页代码,发现
<img class="img_loading"
data-ratio="0.75"
data-s="300,640"
data-src="http://mmbiz.qpic.cn/mmbiz_jpg/fxIVaUUCtBNA247ibbOxCGnOE5SRzbYlpYibCNnfcTiagRTHYDpvNzJZXuxEjLxDfD2tI9Q33HcNEoPHm10tuCfRQ/640?wx_fmt=jpeg"
data-type="jpeg"
data-w="600"
width="auto"
_width="auto" src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg=="
style="margin: 0px; padding: 0px; max-width: 100%; background-color: rgb(238, 237, 235); border-width: 1px; border-style: solid; border-color: rgb(238, 237, 235); background-size: 22px; background-position: center center; background-repeat: no-repeat; background-image: url("data:image/gif;base64,R0lGODlhPAA8APYAAJeXl56enp+fn6Cxxxxxxxxxx SO SO LONG xxxxxx
几点:
- data-src 属性里的才是图片的图片源地址
- src 当 class 为 img_loading 时,为 loading 的 base64 图片。细节处理的不错。(下面会说明此处理解的有问题)
- background-image 才是真正的变态大 base64 图片???
通过 https://codebeautify.org/base64-to-image-converter 转码之后,发现 background-image 就是一张 loading 的 gif 图片,而 src 里的 base64 并不是 loading 图片,是个空白的,我猜测是为了不导致 src 为空时的错误,所以找了个最小的 base64 图片。
这就真相大白了!
所谓的 base64 图片并不是原图,而是 loading 图片。
解决方案
看能否给 summernote 的 paste 加个 hook。
自动将 class 为 img_loading 的 img 做属性替换。
另外,加个字数统计,及限制。
summernote 的 paste hook
参考: https://summernote.org/deep-dive/#onpaste
// onPaste callback
$('#summernote').summernote({
callbacks: {
onPaste: function(e) {
console.log('Called event paste');
}
}
});
替换之后,显示“此图片来自微信公众平台,未经许可不可引用”。
但是,为何加载完的图片,可以显示正常呢?
显示正常的图片
<img class="" data-ratio="0.75" data-s="300,640" data-src="http://mmbiz.qpic.cn/mmbiz_jpg/fxIVaUUCtBNA247ibbOxCGnOE5SRzbYlpYibCNnfcTiagRTHYDpvNzJZXuxEjLxDfD2tI9Q33HcNEoPHm10tuCfRQ/640?wx_fmt=jpeg" data-type="jpeg" data-w="600" width="auto" _width="auto" src="http://mmbiz.qpic.cn/mmbiz_jpg/fxIVaUUCtBNA247ibbOxCGnOE5SRzbYlpYibCNnfcTiagRTHYDpvNzJZXuxEjLxDfD2tI9Q33HcNEoPHm10tuCfRQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1" data-fail="0" style="margin: 0px; padding: 0px; max-width: 100%; height: auto !important; word-wrap: break-word !important; visibility: visible !important; width: auto !important;">
显示为盗链的图片
<img class="img_loading" data-ratio="0.6171875" data-s="300,640" data-src="http://mmbiz.qpic.cn/mmbiz_jpg/fxIVaUUCtBNA247ibbOxCGnOE5SRzbYlpsO04ZR3ia9vkncOU5Oz4hnKrjNefn7rWibJhuvicITPicaKOHicwibYa5EWA/640?wx_fmt=jpeg" data-type="jpeg" data-w="640" width="auto" _width="auto" src="http://mmbiz.qpic.cn/mmbiz_jpg/fxIVaUUCtBNA247ibbOxCGnOE5SRzbYlpsO04ZR3ia9vkncOU5Oz4hnKrjNefn7rWibJhuvicITPicaKOHicwibYa5EWA/640?wx_fmt=jpeg" style="margin: 0px; padding: 0px; max-width: 100%; background-color: rgb(238, 237, 235); border-width: 1px; border-style: solid; border-color: rgb(238, 237, 235); background-size: 22px; background-position: center center; background-repeat: no-repeat; height: 395px !important; word-wrap: break-word !important; visibility: visible !important; width: 640px !important;">
http://mmbiz.qpic.cn/mmbiz_jpg/fxIVaUUCtBNA247ibbOxCGnOE5SRzbYlpYibCNnfcTiagRTHYDpvNzJZXuxEjLxDfD2tI9Q33HcNEoPHm10tuCfRQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1 http://mmbiz.qpic.cn/mmbiz_jpg/fxIVaUUCtBNA247ibbOxCGnOE5SRzbYlpsO04ZR3ia9vkncOU5Oz4hnKrjNefn7rWibJhuvicITPicaKOHicwibYa5EWA/640?wx_fmt=jpeg
对比可见 src 部分是有区别的
&tp=webp&wxfrom=5&wx_lazy=1
这其实是错觉,因为可见图片是之前打开公众号时缓存到浏览器的,清除缓存之后,其实仍然不可见。
在微信小程序端,所有来自腾讯 cdn 的图片,都显示为空白,点击显示大图才可以看到。
使用自己的 CDN 存储
冷静分析了一下,感觉还是不要使用盗链比较稳妥。
- 使用盗链增加了小程序的前端开发复杂度
- 盗链方案哪天失效也未可知
- 盗链图片是否一直存在,具有不确定性
这样实现的方案就变成了
- 解析出里面所有的微信 CDN 图片
- 逐一去掉 base64 属性,上传源地址,后台下载源图,上传到七牛 CDN,再返回七牛的地址
base64 是哪里引入的
这段 base64 loading 的代码是从这个 css 引入的:
var article_improve_combo_css = "//res.wx.qq.com/mmbizwap/en_US/htmledition/style/page/appmsg/page_mp_article_improve_combo3a7ab9.css";
通过 js 加载的。
实现代码
onPaste: function(e) {
var sn = this;
// 如果不适用 setTimeout 你会发现获取的是编辑之前的数据
setTimeout(function () {
// copy weixin 公众号
$(e.currentTarget).find('img[data-src]').each(function() {
var that = this;
var img_src = $(this).data("src");
if (img_src.indexOf('qpic.cn') == -1) {
return;
}
// 上传图片源地址,并获取七牛 CDN 对应的图片地址
$.ajax({
type: "POST",
url: "/upload_xxx",
data: {
wx_image: img_src
},
success: function(data) {
if (data.err_code == 0) {
$(that).replaceWith(function() {
return $('< img src="' + data.data + '">');
});
$(sn).summernote('triggerEvent', 'change');
} else {
alert("图片上传失败");
}
}
});
});
}, 100);
}
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式
谈笑风生
sup (来自: 中国 广东 深圳 电信) 6年前
大象 (来自: 中国 山东 烟台 电信) 6年前
sup (来自: 中国 广东 深圳 电信) 6年前
sup (来自: 中国 广东 深圳 电信) 6年前
大象 (来自: 中国 山东 烟台 电信) 6年前