阅读 42

如何将一个外链图片保存到自己的服务器?

简介

最近一直在开发一款云笔记产品,产品上线后有用户反馈,希望我们提供一个浏览器插件使其能快速收集素材。经过讨论之后,我决定开发一款能为用户提供快速搜集文字、图片功能的浏览器插件。在开发的过程中,遇到了保存图片的问题。假如我们仅仅是将该图片的链接保存,那么到了我们的笔记之后,由于图片链接存在防盗链,则会出现图片加载失败的问题。因此,在前端需要将该图片下载并上传至我们的服务器,然后将新的图片链接保存到笔记中。在开发过程中遇到了一点点的小麻烦,于是记录如下。

responseType的问题

一开始,在使用ajax下载图片时,我首先将responseType设置为blob。responseType的意思是返回响应数据的类型,可选值有很多,例如:arraybuffer、blob、document、json、text等,即我希望返回给我的是一个blob格式的图片。但事与愿违,从别人家的服务器下载东西,你不能指望人家就按照你想要的格式来返回,于是在此碰壁,通过该方式我仅仅拿到了一个字符串,无法将其转为File格式上传。于是我转变思路,不再使用ajax下载,转而使用Image对象来加载图片。

Image

代码如下:

let image = new Image();
image.setAttribute("crossOrigin", "anonymous");
image.onload = function() {
   let canvas = document.createElement("canvas");
   canvas.width = image.width;
   canvas.height = image.height;
   let context = canvas.getContext("2d");
   context.drawImage(image, 0, 0, image.width, image.height);
   let url = canvas.toDataURL("image/png"); //得到图片的base64编码数据
   let file = dataURLtoFile(url,'test.png');
   // 上传自己的服务器
   uploadToServer(file);
 };
 image.src = info.srcUrl;
复制代码

首先创建一个Image实例,并为该实例设置onload方法,即图片下载完成后执行的方法。该方法是将下载好的图片绘制到Canvas,并将Canvas转为base64,完成图片转base64的过程。转为base64后,就可以转为File格式的二进制流上传服务器啦。base64转File的代码如下:

function dataURLtoFile(dataurl, filename) {
  //将base64转换为文件
  let arr = dataurl.split(","),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, {
    type: mime
  });
}
复制代码

上传完成后就可以拿到该图片在自己服务器上的链接了。外链图片上传至自己的服务器更方便我们来管理用户的图片,也保证用户查看图片信息的稳定性。