前端处理后端文件流并下载

关于处理后端文件流并下载

Mine:

今天实现一个功能的时候遇到了问题:

  • 导出二维码到本地并保存为zip文件夹
  • 接口:GET
  • 接口请求时需要在header携带token

参考了之前的项目的办法(url参数携带token):

  • window.open(url,params)后发现无法在header携带token,在新窗口无法获取到正确数据,放弃

因为是GET请求+需要携带token,所以决定先在原窗口发起请求,获取到正确数据后再进行处理并保存文件

  • 在封装request的时候已经进行拦截加入token
  • 封装api的时候声明格式:responseType: ‘blob’
export const apiName = data => {
  return request({
    method: 'get',
    params:data,
    url: '-------url-------',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    responseType: 'blob',
  })
}
  • 在对应页面调用方法时调用
    apiName(params).then( res => {
        if(res.status === 200) {
            //设置格式
            const blob = new Blob([res.data], { type: zip })
            const a = document.createElement('a')
            a.download = '文件名'
            a.href = window.URL.createObjectURL(blob)
            a.click()
            a.remove()
        }
    }).catch( err => { console.log(err)})
其他场景:

(前端处理后端文件流并下载)

场景一

Get请求,无需携带token(或在url参数处携带)

//1.直接用标签接收文件流
<a href="后端文件下载接口地址" >下载文件</a>
    
//2.新建窗口接收文件流
window.open(url)

场景二

Get请求,需要在header处携带token

  • 参考上面

场景三

Post请求,利用原生的XMLHttpRequest方法实现

    function request () {
        const req = new XMLHttpRequest();
        req.open('POST', '<接口地址>', true);
        req.responseType = 'blob';
        req.setRequestHeader('Content-Type', 'application/json');
        req.onload = function() {
          const data = req.response;
          const a = document.createElement('a');
          const blob = new Blob([data]);
          const blobUrl = window.URL.createObjectURL(blob);
          download(blobUrl) ;
        };
        req.send('<请求参数:json字符串>');
      };
    function download(blobUrl) {
      const a = document.createElement('a');
      a.style.display = 'none';
      a.download = '<文件名>';
      a.href = blobUrl;
      a.click();
      document.body.removeChild(a);
    }
    request();

post请求 利用原生的fetch方法实现

function request() {
      fetch('url', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: 请求参数,
      })
        .then(res => res.blob())
        .then(data => {
          let blobUrl = window.URL.createObjectURL(data);
          download(blobUrl);
        });
    }
    function download(blobUrl) {
      const a = document.createElement('a');
      a.style.display = 'none';
      a.download = '文件名';
      a.href = blobUrl;
      a.click();
      document.body.removeChild(a);
    }
    request();
关于Blob

Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。

一个Blob对象就是一个包含有只读原始数据的类文件对象。Blob对象中的数据并不一定得是JavaScript中的原生形式。File接口基于Blob,继承了Blob的功能,并且扩展支持了用户计算机上的本地文件。

应用场景:

File接口基于Blob,继承了Blob的功能并进行了扩展,故我们可以像使用Blob一样使用File对象。

  • 分片上传:通过Blob.slice方法,可以将大文件分片,轮循向后台提交各文件片段,即可实现文件的分片上传
    • 获取要上传文件的File对象,根据chunk(每片大小)对文件进行分片
    • 通过post方法轮循上传每片文件,其中url中拼接querystring用于描述当前上传的文件信息;post body中存放本次要上传的二进制数据片段
    • 接口每次返回offset,用于执行下次上传
initUpload();
      
      //初始化上传
      function initUpload() {
          var chunk = 100 * 1024;   //每片大小
          var input = document.getElementById("file");    //input file
          input.onchange = function (e) {
              var file = this.files[0];
              var query = {};
              var chunks = [];
              if (!!file) {
                  var start = 0;
                  //文件分片
                  for (var i = 0; i < Math.ceil(file.size / chunk); i++) {
                      var end = start + chunk;
                      chunks[i] = file.slice(start , end);
                      start = end;
                  }
                  
                  // 采用post方法上传文件
                  // url query上拼接以下参数,用于记录上传偏移
                  // post body中存放本次要上传的二进制数据
                  query = {
                      fileSize: file.size,
                      dataSize: chunk,
                      nextOffset: 0
                  }
      
                  upload(chunks, query, successPerUpload);
              }
          }
      }
      
      // 执行上传
      function upload(chunks, query, cb) {
          var queryStr = Object.getOwnPropertyNames(query).map(key => {
              return key + "=" + query[key];
          }).join("&");
          var xhr = new XMLHttpRequest();
          xhr.open("POST", "http://xxxx/opload?" + queryStr);
          xhr.overrideMimeType("application/octet-stream");
          
          //获取post body中二进制数据
          var index = Math.floor(query.nextOffset / query.dataSize);
          getFileBinary(chunks[index], function (binary) {
              if (xhr.sendAsBinary) {
                  xhr.sendAsBinary(binary);
              } else {
                  xhr.send(binary);
              }
      
          });
      
          xhr.onreadystatechange = function (e) {
              if (xhr.readyState === 4) {
                  if (xhr.status === 200) {
                      var resp = JSON.parse(xhr.responseText);
                      // 接口返回nextoffset
                      // resp = {
                      //     isFinish:false,
                      //     offset:100*1024
                      // }
                      if (typeof cb === "function") {
                          cb.call(this, resp, chunks, query)
                      }
                  }
              }
          }
      }
      
      // 每片上传成功后执行
      function successPerUpload(resp, chunks, query) {
          if (resp.isFinish === true) {
              alert("上传成功");
          } else {
              //未上传完毕
              query.offset = resp.offset;
              upload(chunks, query, successPerUpload);
          }
      }
      
      // 获取文件二进制数据
      function getFileBinary(file, cb) {
          var reader = new FileReader();
          reader.readAsArrayBuffer(file);
          reader.onload = function (e) {
              if (typeof cb === "function") {
                  cb.call(this, this.result);
              }
          }
      }
  • 通过url下载文件
  • 通过url显示图片
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值