simonyouth / Blog

Record techniques like javascript
0 stars 0 forks source link

react使用fetch请求文件流GET API #4

Open simonyouth opened 5 years ago

simonyouth commented 5 years ago

react使用fetch请求文件流GET API

    使用fetch请求下载docx,xls或其他文件

使用<iframe>和<a>

利用iframe的属性,会创建一个浏览器下载任务

const iframe = document.querySelector('#downloadIframe');
iframe.src = url;

同理,a标签添加href,利用html5新属性download指定下载的文件名也能实现(API指定了文件名的话,并不需要这个属性),需要触发click事件

使用fetch,下载完成监听

用iframe或者a的缺点是不知道下载任务什么时候能结束,无法满足需要loading状态的业务场景。 实现监听的方法也很多,比如cookie等,需要服务端配合。 使用fetch实现:

this.setState({
  loading: true,
});
let filename = '测试.docx';

fetch(url, {
  method: 'GET', // 根据API指定
  headers: {
    'content-type': 'application/json',
  },
}).then(response => {
  // 获取文件名
  // cors模式时headers取不到,
  // 需要服务端添加Access-Control-Expose-Headers暴露需要的headers
  const disposition = response.headers.get('content-disposition');
  if (disposition && disposition.match(/attachment/)) {
    filename = disposition.replace(/attachment;.*filename=/, '').replace(/"/g, ''); // 根据Response Headers返回情况处理
  }
  return response.blob();
}).then(blob => {
  // 生成本地blob下载链接
  const url = window.URL.createObjectURL(new Blob([blob]));
  // 创建元素
  const link = document.createElement('a');
  link.href = url;
  link.setAttribute('download', filename);
  document.body.appendChild(link);

  // 触发click才能下载
  link.click();
  // 移除
  link.parentNode.removeChild(link);
  // 释放ObjectURL资源
  window.URL.revokeObjectURL(url);

  this.setState({
    loading: false,
  })
}).catch(err => {
  // 处理异常
})