el-upload上传文件时返回的字符串异常

问题描述

在使用element-ui的文件上传插件进行资源上传时,后端所返回的数据是一个形如“3297799991516386308”的字符串,也就是资源id。

但是在on-success回调函数中得到的response却是3297800280615081000。显然这个结果并不是随机生成的,因为两者有着明显的相似性。并且这个response并不是字符串,而是一个数字。将这个id传到后台时就会出现与后台资源id不匹配的情况。

问题跟踪

从返回的结果可以推断,我们传入的on-success函数已经成功调用了。打开浏览器的network查看该请求,发现请求返回的是正确的id。于是问题应该定位到el-upload这个插件本身。

打开node_modules中element-ui文件夹,找到upload组件,发现它是这样调用我们传入的on-success函数的(具体的跟踪过程略过):

xhr.onload = function onload() {
    if (xhr.status < 200 || xhr.status >= 300) {
      return option.onError(getError(action, option, xhr));
    }

    option.onSuccess(getBody(xhr));
  };

在浏览器中全局搜索option.onSuccess,然后格式化并在这一行打断点,发现xhr中的response和responseText均为正确的字符串id,但是getBody(xhr)的结果却是错的,这就表示getBody在解析返回结果的时候出错了。于是继续在getBody函数中打断点:

function getBody(xhr) {
  const text = xhr.responseText || xhr.response;
  if (!text) {
    return text;
  }

  try {
    return JSON.parse(text);
  } catch (e) {
    return text;
  }
}

断点走到return JSON.parse(text)时就出了问题,我们这里传入的是正确的字符串“3297799991516386308”,解析的结果却是3297800280615081000。

我们先来看这里的逻辑,它首先试图用JSON.parse来解析返回结果,如果不是标准的JSON字符串,那么这里就会异常,框架捕获到异常后就会直接把原始的字符串返回回来。

这个逻辑看似并没有问题,假如返回的是普通字符串,如"abc",进行parse时就会出现异常,然后正确捕获并返回原始字符串。但是如果字符串的每个字符都是阿拉伯数字,问题就来了,浏览器执行parse时不会抛出异常,而是将其转化为数字,比如:

JSON.parse("123") => 123

按理来说,虽然返回的结果是数字,但是只需要用toString()转为字符串,仍然能得到原始字符串,不会出现上述两者不一致的情况。

出现这个问题的原因就是这个数字太大了,超出了JavaScript所能表示的数字的最大范围,所以浏览器只能用0来填充最后几位。于是原始的阿拉伯数字构成的字符串就被解析成了错误的数值。即“3297799991516386308”被解析为了3297800280615081000。

问题解决

定位到问题之后,解决就变得非常简单,只需要避开直接返回过长的阿拉伯字符串即可。比如可以让后台返回对象格式的数据,或者不要使用纯数字id,或者缩短id的长度,都可以解决这个问题。

说到底,这个问题算是el-upload这个插件的bug,它没有考虑到返回的数据可能是很长的数字字符串这种情况。要解决这类问题,不要怕打开插件源码,查看插件的实现逻辑,因为插件很难保证不会存在bug。这里希望给遇到同样问题的同学一个参考。

发布了37 篇原创文章 · 获赞 90 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41694291/article/details/102843311