将一个图片地址转成文件流(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

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


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

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

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

相关推荐
Pu_Nine_920 分钟前
10 分钟上手 ECharts:从“能跑”到“生产级”的完整踩坑之旅
前端·javascript·echarts·css3·html5
東雪蓮☆1 小时前
从零开始掌握 Web 与 Nginx:入门详解
运维·服务器·前端·nginx
脑子慢且灵1 小时前
【JavaWeb】一个简单的Web浏览服务程序
java·前端·后端·servlet·tomcat·web·javaee
柯南二号1 小时前
【大前端】 断点续传 + 分片上传(大文件上传优化) 的前端示例
前端
前端小超超1 小时前
如何配置capacitor 打包的安卓app固定竖屏展示?
android·前端·gitee
xiaopengbc2 小时前
在Webpack中,如何在不同环境中使用不同的API地址?
前端·webpack·node.js
前端AK君2 小时前
React中台系统如何嵌入到业务系统中
前端
Slice_cy2 小时前
不定高虚拟列表
前端
前端AK君2 小时前
React组件库如何在vue项目中使用
前端
Moonbit2 小时前
MoonBit 再次走进清华:张宏波受邀参加「思源计划」与「程序设计训练课」
前端·后端·编程语言