在React项目,通过post请求获取到文件流,前端如何将文件流下载到本地?

1,887 阅读2分钟

环境:React 16.8.6 + umi-request

需求背景:原来直接操作dispatch调接口就可以下载导出文件了,但是由于服务端上传文件的接口不知道为啥没有开放出来,就没办法转成链接传给前端了,所以前端这边只能相应的改一下了。

一开始,我也很懵,因为之前并没有获取过文件流,都是服务端转成链接给前端的,所以就去网上查找资料,去尝试。终于,功夫不负有心人,终于成功获取到文件并且下载下来,下面就记录一下我的方法吧。

具体要怎么修改呢?

假如我们继续用dispatch的方法继续调用接口,首先项目请求的response就通不过(项目统一配置了umi-request,而且默认返回的是json格式),而且接口返回的是文件流乱码(如下图),还需要对数据进行处理一下。

image.png

这个时候就需要我们稍稍判断调整一下request里面的返回值格式。

request.interceptors.response.use(async response => {
  // 获取Content-Disposition
  const disposition = response.headers.get('Content-Disposition'); 
  if (disposition) {
    return {
      // 将二进制的数据转为blob对象,这一步是异步的因此使用async/await
      blob: await response.blob(), 
      // 处理Content-Disposition,获取header中的文件名
      fileName: decodeURI(disposition.split(';')[1].split('filename=')[1]), 
    };
  }
  // 原先直接从这里开始判断,是否是json
  const data = await response.clone().json();
  if (data.code !== 200) {
    // TODO...
  }
  return response;
});

这里加好之后,我发现接口虽然调用成功了,但是页面一直会有个空的报错弹窗,检查了下代码,发现是request配置里加了统一的业务判断,默认了请求成功会返回一个code=200,这个就没办法了,只能另外写一个request了。

于是我就直接在函数里引用request方法:

const res = await request(
      'api address', {
      baseUrl: 'api域名',
      method: 'POST',
      data: { ...请求传参 },
      responseType: 'blob',
      credentials: 'include', // 默认请求是否带上cookie
});

这样,接口就调用成功了,而且不会有额外的错误提示弹窗。接下来需要将获取到的文件下载到本地:

let blob = new Blob([res.blob], {
      type: 'application/vnd.ms-excel', // excel格式文件
});
let link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'coupon_settlement_list.xlsx'; // 设置下载的文件名称
link.target = '_blank';
link.click();
window.URL.revokeObjectURL(blob);

至此,react项目通过post请求获取文件流并且下载到本地的功能就结束了。