01月14, 2019

多页面传递图片文件问题

最近做一个视频面签项目版本遇到一个坑,然后也是试了很多办法了解了很多资料之后学到的方法。

背景:

视频面签改版前,身份证上传时,后端会返回oss地址,然后前端拿到这个地址传到下一个页面,在录视频时,拿这个图片地址发送给后端做人脸比对。但是改版后,各自之间解耦,后端不将图片传到oss了,所以需要前端把第一步骤的图片转成流传到下一步,然后在下一步将图片流传给后端。

错误方法:

但是要知道图片流是没办法在url中传递给后端的,这个是没办法做到的,传过去之后整个File对象变成了空,取不到任何值。所以这个办法是不可取得。

那么还有一种办法是把图片转成base64然后再传递过去,这个是可以,但是base64非常非常大,但是url传递,get方法传递的参数是有大小限制的,所以会出现有时候只传递了一半的base64,读到的图片流只有一半。

以上两种方法都不行,那怎么办呢?将图片上传完后通过(window.URL || window.webkitURL).createObjectURL(this.fileFlow)将图片转成一个地址,然后传递到下一个页面,通过这个地址再打开这个文件。这样可以吗?答案是:No。传过去后打不开这个文件了。

解决办法:

经过了一天的思考和尝试,找到了一种正确的方法:

将第一步把图片上传后拿到的文件流转成base64,然后将base64存在浏览器的sessionStorage中,然后到第二个页面再读取这个sessionStorage中的图片,拿到这个base64后再将它用canvas画出来,然后再将canvas图片转为文件blob对象,要知道FILE对象其实真正是继承BLOB对象的,所以转成BLOB对象就是这个图片的正确方式了。

这个时候需要注意这个blob对象的name就是Blob,所以后端如果获取图片name的话其实是会获取不到的,那么有什么办法添加name吗?目前应该是不可以。为什么不能呢?因为blob对象只对外提供了两个只读属性,分别是Blob.size和Blob.type。请参考https://developer.mozilla.org/zh-CN/docs/Web/API/Blob MDN上对Blob有详细的说明。

扩展:

File对象,File对象是基于BLOB接口进行开发和扩展的。file对象是特殊的blob。通常情况下,File对象是来自用户在一个input元素上选择文件后返回的filelist对象,也可以是来自由拖放操作生成的DataTransfer对象,或者来自HTMLCanvasElement上的mozGetAsFile()API。最后一个就是这一次咱们使用的把图片转为文件流的方法。

File对象对外也提供了很多个属性,但是这些属性基本上都是只读属性,比如文件的名字,文件的大小,文件的类型等。请参考https://developer.mozilla.org/zh-CN/docs/Web/API/File MDN上对Blob有详细的说明。

代码部分:

// A页面的操作

// 将图片转为base64存储在sessionStorage
function fileReader(file, callback) {
     const reader = new FileReader();

     reader.addEventListener('load', () => {
            const result = reader.result;
            this.imageUrl = result;
            sessionStorage.setItem('file_key', result);
            callback && callback(result);
     }, false);
    reader.readAsDataURL(file);
}

// B页面的操作
function init() {
     // 图片base64转canvas转文件流再上传
     const image = new Image();
     image.onload = async function(){
          const canvas = image2Canvas(this);
          const blob = await canvas2Blob(canvas);
         upload(blob);// 自行实现上传
    }
    image.src = sessionStorage.getItem('file_key');
}

// 图片转canvas
function image2Canvas(image) {
    const canvas = document.createElement('CANVAS');
    const ctx = canvas.getContext('2d');
    canvas.width = image.width;
    canvas.height = image.height;
    ctx.drawImage(image, 0, 0);
    return canvas;
}

 // canvas转换成BLOB
function canvas2Blob(canvas) {
     return new Promise((resolve, reject) => {
          canvas.toBlob((blob) => {
             resolve(blob);
          });
     }, 'image/png');
}

以上就是这次在本项目中学习到的文件流多页面传输的内容,希望对你们有帮助~~

本文链接:https://luodao.me/post/fileflow.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。