chrome种preview和response数据不一致,前端的参数在数据库查找不到

1,399 阅读4分钟

我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!

最近项目联调时候遇到一个问题,前台请求不到数据,后台postman里面确实请求正常,真是太令人费解了。。。

参数发给后台让查找数据库,结果数据库中查找不到该参数。。。

多方排查后发现,接口在preview和response里面的数据竟然不一致!!!

priveiw数据 image.png

response数据

image.png

数据为Long型,返回给浏览器以后,浏览器转换数据格式的时候出现问题。JS在处理返回数据类型是Long的时候,Long类型位数过长(js里面number类型的数值范围是2的53次方减1,即9007199254740991),精度会丢失一部分。

后来反应过来又去看response的数据发现这里返回的数据是正常的,preview是丢失后的数据

解决

只要服务端把数据转成string就可以了

深入研究

  • Number对象是采用64位存储的,即8个字节 * 8位 = 64位
  • 操作符在操作Number类型时,实际是操作的32位
  • 在底层再把32位转换成64位进行处理

所以

  • 最大的整数就是2的32次方减1
  • 即 2 ** 32 - 1
  • 数组索引时也能佐证,因为数组的索引是整数,最大的索引就是 2 ** 32 - 1 即4294967295

JAVA侧返回的订单编号或用户ID都整型,在Web侧会出现后面2位超出JavaScript整数取值范围

如下:

java = 123456789012345678; // 一共18个数
js   = 123456789012345600; // 一共16个数外加2个0

在新的ECMAScript规范中也添加了1个Number常量最大安全整数Number.MAX_SAFE_INTEGER

  • 这个里面的最大整数和上面的一样,是16个数
  • 即2的53次方-1 2 ** 53 - 1

image.png

double 浮点数结构如下:

image.png

  • 1 位符号位
  • 11 位指数位
  • 52 位尾数位

使用 52 位表示一个数的整数部分,那么最大可以精确表示的数应该是 2^52 - 1 才对, 就像 64 位表示整数时那样: 2^63 - 1 (去掉 1 位符号位)。 但其实浮点数在保存数字的时候做了规格化处理,以 10 进制为例:

**

20*10^2 => 2*10^3 //小数点前只需要保留 1 位数

对于二进制来说, 小数点前保留一位, 规格化后始终是 1.***, 节省了 1 bit,这个 1 并不需要保存。

总结

出现上面原因还是因为后台的id超过了int的最大范围。但是记得最近JS出了bigInt类型来表示大整数,那是不是页能用bigInt来定义特别大的id呢?

BigInt 是一种内置对象,它提供了一种方法来表示大于 >  2^53 - 1 的整数。这原本是 Javascript中可以用 Number表示的最大数字。BigInt 可以表示任意大的整数。

可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n,或者调用函数BigInt()

const theBiggestInt = 9007199254740991n;

const alsoHuge = BigInt(9007199254740991);
// ↪ 9007199254740991n

const hugeString = BigInt("9007199254740991");
// ↪ 9007199254740991n

const hugeHex = BigInt("0x1fffffffffffff");
// ↪ 9007199254740991n

const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");
// ↪ 9007199254740991n

它在某些方面类似于 Number,但是也有几个关键的不同点:

  • 不能用于 Math 对象中的方法;
  • 不能和任何 Number实例混合运算,两者必须转换成同一种类型。在两种类型来回转换时要小心,因为 BigInt 变量在转换成 Number 变量时可能会丢失精度。