Bootstrap

文件流实现下载、预览

公司系统出于安全性考虑,不允许控制台出现文件地址,避免有人把地址复制给没有该文件查看权限的人。所以只能后端返回文件流。

实现下载很简单,以下代码适合任何类型的文件下载:

 const downloadFile = (file) => {
    axios({
      method: requestMethod,
      url: requestUrl,
      headers: {
        Accept: 'text/plain, application/json',
        ...
      },
      responseType: "arraybuffer"
    }).then(res => {
      console.log(res)
      const { data } = res;
      if (res.headers["content-type"].startsWith("application/json")) {
        let enc = new TextDecoder("utf-8");
        let res = JSON.parse(enc.decode(new Uint8Array(data))); //转化成json对象
        console.log(res)
        message.error(res.resp_msg)
        throw new Error(res.resp_msg);
      }
      const blob = new Blob([data]);
      const url = window.URL.createObjectURL(blob); // URL.createObjectURL(object)表示生成一个File对象或Blob对象
      let dom = document.createElement("a"); // 设置一个隐藏的a标签,href为输出流,设置download
      dom.style.display = "none";
      dom.href = url;
      let fileName = file.fileName;
      dom.setAttribute("download",fileName); // 指示浏览器下载url,而不是导航到它;因此将提示用户将其保存为本地文件
      document.body.appendChild(dom);
      dom.click();
    }).catch(e => {
      console.log(e)
    })
    //下面这种也行,但是如果接口报错没有提示,感觉用户体验不好
    /* 
    let xhr = new XMLHttpRequest()
    xhr.responseType = 'blob'
    xhr.onload = function() {
      const url = window.URL.createObjectURL(xhr.response);
      const a = document.createElement('a');
      a.href = url;
      a.download = file.fileName;
      a.click();
    }
    xhr.open(requestMethod, requestUrl)
    xhr.send()*/
  };

然后是预览,文件有word类型和图片。我们的word是由后端把文件转为pdf类型,饭后返回pdf文件流。

  const previewClick = async (records) => {
    if(records.fileName.indexOf('.zip')>0 ||
        records.fileName.indexOf('.rar')>0){
      message.info('压缩包文件不可预览')
      return
    }
    const fileId = records.fileId;
    if(records.fileType.indexOf('image/')>=0||records.fileType.indexOf('pdf')>=0){
      // window.open(fileUrl); // 之前后端返回文件地址的做法
      getFileStream(fileUrl, records.fileType.indexOf('image/')>=0?records.fileType:null)
    }else{
      const hide = message.loading('正在请求 PDF 地址');
      const res = await services.getPdfStream(fileId)
      if (res.resp_code === 200) {
        hide();
        // console.log(res.datas)
        getFileStream(res.datas, null)
      } else {
        message.warning('无可用的文件预览地址');
        hide();
      }
    }
  };
  const getFileStream = (id, type) => {
    let requestUrl = requestUrl
    let xhr = new XMLHttpRequest()
    xhr.responseType = 'blob'
    xhr.onload = function() {
      let blob = xhr.response
      // console.log(blob, 'blob')
      let data
      if(type){
        data = new Blob([blob], { type: type }); // 根据实际的图片类型进行设置,常见的类型有            image/png,image.jpeg
      }else{
        data = new Blob([blob], {
          type: 'application/pdf;charset=UTF-8'
        })
      }
      let url = URL.createObjectURL(data);
      // console.log(url)
      window.open(url)
    }
    xhr.open(requestMethod, requestUrl)
    xhr.send()
  }

上面这个方法只适用于预览图片和后端可以转为pdf的word文档,excel和其他office文件没法实现。

;