vue 对文件进行预览与下载时的响应错误进行处理

498 阅读2分钟

场景一 :下载表格文件

前端提供表格的下载功能,后端响应结果成功时是文件流,失败时为JSON数据格式,面对这两种情况,前端拿到响应结果后需要对两种格式进行判断。

  • 成功格式

    image.png

  • 失败格式

    image.png

  • 前端处理

export function exportMethod(requst, callBack) {
  const { url, data, params, method } = requst
  axios({
    headers: {
      // Authorization: "Bear " + getToken(),
    },
    method,
    url,
    data,
    params,
    responseType: "blob",
  })
    .then((res) => {
      const reader = new FileReader(); // 创建读取文件对象
      reader.readAsText(res.data, "utf-8"); // 设置读取的数据以及返回的数据类型为utf-8
      reader.onload = () => {
        try {
	  // 如果是失败格式,则会被解析为JSON,否则会抛出语法异常
          const data = JSON.parse(reader.result);
          if (data.code && data.code !== 20000) {
            callBack && callBack(false);
            return MessageOnce.warning(data.message);
          }
        } catch (err) {
          // 如果是成功格式,则会进入下载流程
          const link = document.createElement("a");
          link.style.display = "none";
          const blob = new Blob([res.data], {
            type: "application/vnd.ms-excel",
          });
          link.href = URL.createObjectURL(blob);
          link.download = requst.fileName;
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link);
          callBack && callBack(true);
        }
      };
    })
    .catch((error) => {
      console.log(error);
    });
}

场景二:对(pdf/图片...)文件使用iframe进行预览

  • 与场景一的表格下载相似,后端同样返回两种格式的响应结果,如果判断为成功则使用iframe加载预览,否则弹出警告

  • 失败格式:code= 50000 (图不对文,不过没关系,都是一样的理)

    image.png

  • 前端处理

    第一步:拿到响应结果的blob格式,需要发送请求时携带 responseType: "blob"请求格式。

    第二步:使用 FileReader 拿到响应结果的文件流,因为失败格式是JSON格式的,所以使用try包裹对文件流进行JSON格式化,如果成功则说明得到的是失败格式,如果失败则进入catch层进行转换操作。

    第三步:我们需要使用 URL.createObjectURL提供给iframe加载的url,使用 URL.createObjectURL之前需要得到一个blob文件,这里我们不能直接拿第一步得到的blob,因为从第一步拿到的blob中无法获取文件的真实类型,只能使用其他库方法来得到,这里选择了使用 file-type 来得到真实文件类型(如果是vue2的话,亲测需要下载 16.5.4版本的),得到真实类型后,创建一个blob对象,最后生成url,iframe此时能够正确加载了。

    async requstPreview(pdfPath) {
          return new Promise((resolve, reject) => {
            filePreview(pdfPath).then((res) => {
              const reader = new FileReader()
              reader.readAsText(res, "utf-8")
              reader.onload = async() => {
                try {
                  const data = JSON.parse(reader.result)
                  if (data.code && data.code === 50000) {
                    return reject()
                  }
                } catch (err) {
                  const { mime } = await FileType.fromBlob(res)
                  const blob = new Blob([res], {
                    type: mime,
                  })
                  resolve(window.URL.createObjectURL(blob))
                }
              }
            }).catch((e) => {
              reject(e)
            })
          })
        }