要求下载文档显示loading动画

398 阅读2分钟

前言

产品经理: 你这下载按钮点了没反应啊!
你: 那是后台太慢了。
产品经理: 后台去优化,你给我加一个loading动画

遇到这种情况,以前我都是跟后台商量说: 这个接口返回的是文件流,我捕捉不到,所以没办法判断loading啥时候结束。需要拆成两个接口: 1. 普通请求,告诉后台该整理数据里。loading显示,请求回来后loading结束。2. 下载数据

两个接口

就是上面说的方案。

流程

  1. 前端显示loading。请求接口1,传条件,告诉后台准备数据;
  2. 后台根据请求值开始准备数据;
  3. 后台准备完成后,将数据存成文件放在服务器里,并返回接口1
  4. 前端接受到接口1的响应后,结束loading,同时请求接口2,下载接口1准备的文件。

注: 为了保证接口2下载的数据是第一次接口1所准备的,所以第3步接口1的返回值需要给一个id。请求接口2的时候把id带给后台。

结论

目测没有什么问题,是的,我之前用的时候也可以满足需求正常使用。但是有一天,后台提出,要多台服务器,做负载均衡。这问题就出现了: 接口1是A服务器接收的请求,准备的文件也放在了A服务器,但但但接口2再请求的时候不一定是A服务器,所以找不到接口1准备的文件了。

说: 只定一台服务器放准备的文件即可,我看行,但是没这样做。

responseType = "blob"

上代码

function downloadFile(url: string, params: any, cb: any) {
  const ajaxUrl = window.location.origin + url + "?params=" + JSON.stringify(params);
  const xhr = new XMLHttpRequest();
  xhr.open("GET", ajaxUrl, true);
  xhr.responseType = "blob";       // 关键
  xhr.onload = function() {
    if (this.status === 200 || this.status === 201) {
      const blob = this.response;
      const reader = new FileReader();
      reader.readAsDataURL(blob);
      reader.onload = function(e: any) {
      	
        // 文件名由后台控制
        const disposition: any = xhr.getResponseHeader("Content-disposition");
        const arr = disposition.split(";");
        const filenameStr = arr.find((i: string) => i.indexOf("filename") > -1);
        let filename = decodeURI(escape((filenameStr.split("=")[1])));
        filename = filename.replace(`"`, "");
        filename = filename.replace(`"`, "");
        
        const a: any = document.createElement("a");
        a.download = filename;
        a.href = e.target.result;
        const root: any = document.getElementById("react-root");
        root.appendChild(a);![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/72d514a2c97c4ad5a999f33bb06c1be9~tplv-k3u1fbpfcp-zoom-1.image)
        a.click();
        root.removeChild(a);
        cb();
      };
    }
  };
  xhr.send();
}

效果如下图,一个接口