下载文件的提示信息异常处理

878 阅读3分钟

前言

最近做了一个关于富文本编辑器的模块需求,但凡涉及这个玩意儿都要脱层皮。做完这个迭代后,有了点新的想法,想在掘金上记录下一些比较实际且常用的问题处理方式。

问题描述与分析

关于这个问题的需求背景我就不具体展开了,就简单描述下针对这个问题本身的一些情况。在没有上传任何文件或者上传的文件全部删除的情况下,点击打包下载文件按钮,前端页面显示的message提示为:

image.png

查看http状态码显示的是500,后端返回的message是“未找到文件数据”。那么问题来了,为什么前端页面给的错误信息提示与后端返回的meaasge不符呢?

image.png

这时候,在前端获取返回结果失败的情况下打印信息

image.png

打印出来的结果如👇所示: image.png

返回的是一个 HttpErrorResponse 类型,一般情况下后端返回的message会位于该类型的error中,而我们展开error获得的却是Blob对象,如果是初次遇到这种问题是不是觉得不可思议?后端接口返回的message和code等信息都不翼而飞了!

机灵的同学就会想到,既然这个下载功能是后端返回blob文件流的形式,那么前端在service层应该是做了一些处理了。没错,对于接口请求响应类型我这边设置为blob,但也仅此而已,并没有对请求失败时后端返回的message动手脚呀。

image.png

🤔再三,那么只有一种可能了,就是前端在封装好的响应拦截的文件里做了一些处理,这样也就解释了为什么页面给的错误信息是我们不想要的了。我在 auth-token.interceptor.ts 文件中找到了当http状态码为500的情况下,前端对于message的处理:

image.png

通过debug或者直接查看上述代码,我们可以发现,我们打印的error.error是Blob对象,所以肯定为object的,但是下一步给erro.error.message做序列化的时候,我们之前打印的error.error里面可没有message,只有Blob对象的大小和类型,那么代码流程就会走msg不存在的情况了,这时候我们对这段模版字符串进行解析。

image.png

在定义的statusMap里,我们发现status为500的情况下,message前端提供为“内部服务器错误“,这不正是一开始前端页面给的错误信息提示嘛!

解决方案

解决问题的突破口就在于对error.error做typeof类型判断为object的时候,再去细化一下,因为Blob是object的一种,这时候我们考虑下在error.error为Blob的情况下,msg的处理方式。

通过查找MDN,我们发现要读取Blob或者File对象的内容需要用到 FileReader 这个API。通过new这个对象创造的实例可以调用 readAsText 这个方法来读取指定的Blob中的内容,而onload事件会在读取操作完成时触发,而实例的result属性即是读取的结果。

image.png

有了解决方案,那么接下来二话不说,直接coding来实现吧!

代码实现

if (error.status === 500) {
    let msg;
    if (typeof error.error === 'object') {
      if (error.error instanceof Blob) {
        const reader = new FileReader();
        reader.onload = () => {              
          msg = reader.result.toString();
          try {
            const responseErrorMsg = JSON.parse(msg);
            this.msgService.error(responseErrorMsg.message);
          } catch {
            this.msgService.error(msg);
          }
        };
        reader.readAsText(error.error);
        return throwError(error);
      }

      msg = JSON.stringify(error.error.message);
    } else if (typeof error.error === 'string') {
      const errorTextArr = error.error.match(/[\u4e00-\u9fa5]+/gm);
      if (!!errorTextArr) {
        msg = errorTextArr.join(',');
      }
    }

    if (!msg) {
      msg = `${statusMap['status.' + error.status]}`;
    }
    this.msgService.error(msg);
}

最终,前端页面正确显示了后端返回的错误提示:

image.png