将一个图片地址转成文件流(File)再上传

写在开头

最近,小编在业务中遇到一个图片转存的场景。

领导🤠:大概过程就是,接口会给我返回一个图片列表数据,图片路径是全路径,但是路径中的域名是其他系统的,必须要在用户选择图片的时候将图片重新转存到自个的系统上,防止其他系统删除图片对此有影响。

我😃:Em...很合理的需求。

(但是,和有什么关系?我只是一个前端小菜鸡呀,不祥的预感.......)

我😃:(卑微提问)这个过程不是放后端做比较合理一点?

后端大哥😡:前端不能做?

我😣:可以可以,只是...这个好像会跨域?

后端大哥😠:已经配置了请求头('Access-Control-Allow-Origin': '*')。

我😖:哦,好的,我去弄一下。(*******此处省略几万字心理活动内容)

第一种(推荐)

那么,迫于......不,我自愿的,我们来看看前端要如何完成这个转成过程,代码比较简单,直接贴上来瞧瞧:

javascript 复制代码
async function imageToStorage(path) {
  // 获取文件名
  const startIndex = path.lastIndexOf('/');
  const endIndex = path.indexOf('?');
  const imgName = path.substring(startIndex + 1, endIndex);
  // 获取图片的文件流对象
  const file = await getImgToFile(path, imgName);
  // TODO: 将File对象上传到其他接口中
}

/**
 * @name 通过fetch请求文件,将文件转成文件流对象
 * @param { string } path 文件路径全路径
 * @param { string } fileName 文件名
 * @returns { File | undefined }
 */
function getImgToFile(path, fileName) {
  const response = await fetch(path);
  if (response) {
    const blob = await response.blob();
    const file = new File([blob], fileName, { type: blob.type });
    return file;
  }
}

上述方式,在后端配置了允许跨域后,正常是没有什么问题的,也是比较好的一种方式了。😃

但是,在小编实际第一次编码测试后,却还是遇上了跨域。😓

一猜应该就是后端实际还没配置好,问了一下。

后端大哥😑:还没部署,一会再自己试试。

我😤:嗯嗯。

第二种

等待的过程,小编又在网上找了找了,找到了第二种方式,各位看官可以瞧瞧:

javascript 复制代码
/** @name 将图片的网络链接转成base64 **/
function imageUrlToBase64(imageUrl: string, fileName: string): Promise<File> {
    return new Promise(resolve => {
      const image = new Image();
      // 让Image元素启用cors来处理跨源请求
      image.setAttribute('crossOrigin', 'anonymous'); 
      image.src = imageUrl + '&v=' + Math.random();
      image.onload = () => {
        const canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;
        const context = canvas.getContext('2d')!;
        context.drawImage(image, 0, 0, image.width, image.height);
        // canvas.toDataURL
        const imageBase64 = canvas.toDataURL('image/jpeg', 1); // 第二个参数是压缩质量
        // 将图片的base64转成文件流
        const file = base64ToFile(imageBase64, fileName);
        resolve(file);
      };
    });
  }
  /** @name 将图片的base64转成文件流 **/
function base64ToFile(base64: string, fileName: string) {
    const baseArray = base64.split(',');
    // 获取类型与后缀名
    const mime = baseArray[0].match(/:(.*?);/)![1];
    const suffix = mime.split('/')[1];
    // 转换数据
    const bstr = atob(baseArray[1]);
    let n = bstr.length;
    const u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    // 生成文件流
    const file = new File([u8arr], `${fileName}.${suffix}`, {
      type: mime,
    });
    return file;
}

这第二种方式由于要先把图片绘制到 canvas 再去转成 base64 再去转成文件流,小编用 console.time 稍微测了一下,每次转化过程都要几百毫秒,图片越大时间越长,挺影响性能的。

所以,小编还是推荐使用第一种方式,当然,最稳妥的方案是后端去搞最好了。😉

网上很多都说第二种方式可以直接绕过跨域,各种谈论。😪

主要就是这个 crossOrigin 属性。MDN解释

它原理是通过了 CORS

或者可以再看看这个解释:传送门


至此,本篇文章就写完啦,撒花撒花。

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。

老样子,点赞+评论=你会了,收藏=你精通了。

相关推荐
newxtc13 分钟前
【爱给网-注册安全分析报告-无验证方式导致安全隐患】
前端·chrome·windows·安全·媒体
一个很帅的帅哥30 分钟前
axios(基于Promise的HTTP客户端) 与 `async` 和 `await` 结合使用
javascript·网络·网络协议·http·async·promise·await
dream_ready1 小时前
linux安装nginx+前端部署vue项目(实际测试react项目也可以)
前端·javascript·vue.js·nginx·react·html5
编写美好前程1 小时前
ruoyi-vue若依前端是如何防止接口重复请求
前端·javascript·vue.js
flytam1 小时前
ES5 在 Web 上的现状
前端·javascript
喵喵酱仔__1 小时前
阻止冒泡事件
前端·javascript·vue.js
GISer_Jing1 小时前
前端面试CSS常见题目
前端·css·面试
某公司摸鱼前端1 小时前
如何关闭前端Chrome的debugger反调试
javascript·chrome
八了个戒2 小时前
【TypeScript入坑】什么是TypeScript?
开发语言·前端·javascript·面试·typescript
不悔哥2 小时前
vue 案例使用
前端·javascript·vue.js