前端快照方案实践

2,654 阅读2分钟

前言

首先声明该文章是看了高质量前端快照方案:来自页面的「自拍」@ 云音乐前端技术团队后实践写的笔记,为了方便之后回顾,如果有小伙伴和我一样遇到了相同的情况也可以有个参照。

实践

高质量前端快照方案:来自页面的「自拍」@ 云音乐前端技术团队原文章写的很详细,想要全面了解相关内容可查看原文,这里为只针对我个人的需求做一些合并图片的分析。

需求

根据用户的二维码和海报生成一张新的图片分享出去。就涉及到将两张图片合成一张的需求。

使用 canvas

第一想法就是使用 ctx.drawImage(),去绘制图像,然后使用 ctx.toDataURL() 导出绘制图像的地址。

合并图片的demo完整代码

// 核心代码
let canvas = document.createElement('canvas')
let context = canvas.getContext('2d')
this.$refs.box1.onload = ()=>{
  // 画布上第一次画的内容,0,0表示坐标
  context.drawImage(this.$refs.box1,0,0)
  // 画布上第二次画的内容,30,30表示坐标,层级会比之前的高
  context.drawImage(this.$refs.box2,30,30)
  console.log('url',canvas.toDataURL());
}

浏览器安全限制

可能你使用了相同的 canvas api 去导出一个合并的图片地址时发生如上报错。原因有两点

  1. 你使用的图片地址未设置允许跨域。在浏览器中输入你的图片地址查看,想我这张图片存储的服务器允许跨域访问
  2. 浏览器中 img 元素是否设置了允许跨域,img 本身是没有跨域问题的,但是使用 canvas api 如 toDataURL,toBlob,getImageData 由于浏览器的限制会产生跨域问题。

解决跨域限制

根据产生跨域的原因

  1. 方式一就是将图片存储的服务设置 Access-Control-Allow-Origin*,如果使用外部的图片地址,如微信的二维码,可以使用自家的服务做一层代理,拿node举例设置如下
// 
const cors = require('@koa/cors')
app.use(
  cors()
)
  1. 写一个接口,将图片地址转换成二进制的数据返回给客户端,好处就是可以解决多个不同域名下的图片地址,而不需要将所有图片都存储在自家的服务器上。
// 服务端代码
router.get('/image',async ctx=>{
  let url = await convertImage(ctx.query.url)
  ctx.set('Content-Type', 'image/png');
  ctx.set('Cache-Control', 'max-age=2592000');
  ctx.body = url
})
function convertImage(url) {
  return new Promise((resolve,reject)=>{
    request({
      url,
      encoding:'binary'
    },(error,response,body)=>{
      if (error) {
        console.log(error)
        reject(error)
    }
    // 返回二进制文件
    resolve( Buffer.from(body,'binary'))
    })
  })
}

// 客户端代码这里由于不是同源的,所以我把完整路径都带上了
<img src="http://localhost:9000/react/image?url=URL" alt="">

最后

只写了自己使用合并图片时解决的方案,更多详细内容参考高质量前端快照方案:来自页面的「自拍」@ 云音乐前端技术团队