后端要采用ArrayBuffer上传文件

最近做了个不一样的上传方式,其实上传文件是最常见的交互方式,前端上传的方式也很多。常见的有:

1. form + input 上传

<form action='uploadFile.php' enctype="multipart/form-data" type='post'>
  <input type='file'>
  <input type='hidden' name='userid'>
  <input type='hidden' name='signature'>
  <button>提交</button>
</form>

优点:使用简单方便,兼容性好,基本所有浏览器都支持。

缺点:提交数据后页面不会跳转,前端无法知道什么时候上传结束,传输别的参数需要借助 type="hidden" 来完成

2. 使用 FromData 上传

使用js构造form表单的形式提交,简单高效,也是现在比较流行的做法

<input type="file" id="file" />

<script>
let el = document.getElementById('file');
el.onchange = function(e) {
    const file = e.target.files[0];
    const formData = new FormData();
    formData.append("userid", userid);
    formData.append("signature", signature);
    formData.append("file", file);
}
</script>

缺点:不兼容IE10以下的浏览器

很遗憾。。我们的后端这两种均不支持。。需要采用文件流的形式上传

3. 采用ArrayBuffer 方式上传

let el = document.getElementById('file');
el.onchange = function(e) {
    const file = e.target.files[0];
    const reader = new FileReader();
    reader.onload = async (e) => {
      const buffer = reader.result; // 获取到一个文件的Arraybuffer
      this.uploadBuffer(buffer); // 上传文件
    };
    reader.readAsArrayBuffer(file);
}

以上写法看起没什么问题。。也能正常上传。但是文件超过10M以上的数据,就会卡死。如果文件更大,浏览器就直接崩溃了

这时就需要将ArrayBuffer 进行切片上传

async uploadBuffer (buffer, startSzie = 0, index = 1) {
      let endSize = index * this.chunkSize;
      let res = buffer.slice(startSzie, endSize);
      try {
        // 上传视频片段
        const { data } = await axios({
          url: this.uploadUrl,
          method: 'post',
          data: res,
          headers: {
            'Content-Type': '',
            'Content-Range': `bytes ${startSzie}-${index * this.chunkSize}/${this.videoSzie}`
          }
        });
        const { start, path, success } = data;
        if (success) {
          // 如果还有剩余,则递归上传,接口不支持并发
          if (endSize <= this.videoSzie) {
            this.uploadBuffer(buffer, start, ++index);
          } else {this.uploadSuccess = true;
            const params = {
              userId: this.userId,
              author: this.userName,
              name: this.videoFileName,
              filePath: path,
              serverId: this.serverId,
              type: 1
            };
            // 全部片段上传成功之后,保存视频
            const saveInfo = await IO.saveVideoInfo(params);
            if (saveInfo.list) {
              this.videoUrl.url = saveInfo.list;
            }
          }
        }
      } catch (error) {
        this.$toast('視頻上傳失敗');
        this.closeVideo();this.uploadSuccess = true;
      }
    }

缺点:大文件上传会导致浏览器崩溃, 无法添加其他参数。上传相对较慢

兼容性还可以。基本能满足我们现在的业务场景

参考:

  https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsArrayBuffer

  https://www.w3cschool.cn/javascript_guide/javascript_guide-d2h126ad.html

原文地址:https://www.cnblogs.com/shenjp/p/13749816.html