如何将远程图片(imgUrl)上传给服务器?

594 阅读2分钟

项目中,一般都是将本地图片上传给服务器,但是最近项目中,居然遇到要将远程获取的图片(url链接)再次上传给服务器的需求。

好嘛,挑战又来了!

最终,经过一番查搜与实践,终于找到了实现方案。

因为后端上传接口中的file参数需以文件流的形式上传,所以我们如果想正确上传,那就需要将手里的imgUrl通过某种方式转为文件流。

那如果将imgUrl转为文件流呢?

需要经历如下两步:

一: 将imgUrl 转 base64Url

imgUrl转为base64Url,我亲测了两种方式(还有其他方法欢迎评论区补充),均可实现。

方式1:利用canvas + Image() 实现

function imgUrlToBase64(imgUrl) {
    return new Promise((resolve, reject) => {
         let canvas = document.createElement('canvas');
         const ctx = canvas.getContext('2d');
         const img = new Image();
         img.crossOrigin = 'Anonymous';// 允许跨域
         img.src = imgUrl
         img.onload = function() {
           canvas.height = img.height;
           canvas.width = img.width;
           ctx.drawImage(img,0,0);
           const dataURL = canvas.toDataURL('image/png');
           resolve(dataURL)
           canvas = null;
         } 
         img.onerror = function (err) {
          reject(err)
        }
    })
 }

注意:

后端需给图片服务器配置Access-Control-Allow-Origin信息,前端需设置crossOrigin属性为anonymous,不然会出现跨域问题。

方式二:利用ajax + FileReader() 实现

function imgUrlToBase64(imgUrl) {
    return new Promise((resolve, reject) => {
         const xhr = new XMLHttpRequest();
         xhr.open("get", imgUrl, true);
         xhr.responseType = "blob";
         xhr.onload = function () {
            if (this.status == 200) {
                const blob = this.response;
                const fileReader = new FileReader();
                fileReader.onloadend = function (e) {
                  resolve(e.target.result)
                };
                fileReader.readAsDataURL(blob)
            }
         }
        xhr.send();
    })
 }

注意:此方法虽然没有跨域问题,但因为是blob地址,所以图片不宜过大,否则超过blob尺寸限制就会有问题。

二:将base64Url转为文件流

imgUrl转为base64Url后,我们再通过如下方法,将base64Url转为二进制文件流。

function base64Tofile(base64Url,fileName) {
    const arr = base64Url.split(',');
    const mime = arr[0].match(/:(.*?);/)[1];
    const bstr = atob(arr[1]);
    let n = bstr.length; 
    const u8arr = new Uint8Array(n);
    while(n--){
       u8arr[n] = bstr.charCodeAt(n);
    }
    //转换成file对象
    return new File([u8arr], fileName, {type: mime});
    //转换成成blob对象
    //return new Blob([u8arr],{type: mime});
}

经历以上两步后,我们调取后端上传接口,把file以参数形式传过去就能将远程图片上传到服务器了。伪代码如下:

 const base64Url = await this.imgUrlToBase64(imgUrl)   
 const file = await this.base64Tofile(base64Url, '图片1.png')
 const formData = new FormData()
 formData.append('file', file)
 formData.append('type', 1) // 关系类型
 formData.append('filePath', 'follow-record')
 const contextType = { 'Content-Type': 'multipart/form-data'  }
 // 上传接口
 uploadFile(formData, contextType)

以上方式,如有不足,欢迎指正!