copy 微信公众号文章复制到 summernote, 图片变成了 base64

文章目录

    问题

    一个旅行社的客户反馈,从他们微信公众号复制之前的文章,粘贴到微信小程序的后台富文本编辑器 (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
    

    几点:

    1. data-src 属性里的才是图片的图片源地址
    2. src 当 class 为 img_loading 时,为 loading 的 base64 图片。细节处理的不错。(下面会说明此处理解的有问题)
    3. 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 存储

    冷静分析了一下,感觉还是不要使用盗链比较稳妥。

    • 使用盗链增加了小程序的前端开发复杂度
    • 盗链方案哪天失效也未可知
    • 盗链图片是否一直存在,具有不确定性

    这样实现的方案就变成了

    1. 解析出里面所有的微信 CDN 图片
    2. 逐一去掉 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 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式