文章详情: 关于后端返回数据中的大数字问题(为什么404)

之所以请求文章详情返回 404 是因为我们请求发送的文章 ID (article.art_id)不正确。

JavaScript 能够准确表示的整数范围在-2^532^53之间(不含两个端点),超过这个范围,无法精确表示这个值,这使得 JavaScript 不适合进行科学和金融方面的精确计算。

Math.pow(2, 53) // 9007199254740992

9007199254740992  // 9007199254740992
9007199254740993  // 9007199254740992

Math.pow(2, 53) === Math.pow(2, 53) + 1
// true
复制代码

上面代码中,超出 2 的 53 次方之后,一个数就不精确了。 ES6 引入了Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。

Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1
// true
Number.MAX_SAFE_INTEGER === 9007199254740991
// true

Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER
// true
Number.MIN_SAFE_INTEGER === -9007199254740991
// true
复制代码

上面代码中,可以看到 JavaScript 能够精确表示的极限。

后端返回的数据一般都是 JSON 格式的字符串

'{ "id": 9007199254740995, "name": "Jack", "age": 18 }'
复制代码

如果这个字符不做任何处理,你能方便的获取到字符串中的指定数据吗?非常麻烦。所以我们要把它转换为 JavaScript 对象来使用就很方便了。

幸运的是 axios 为了方便我们使用数据,它会在内部使用 JSON.parse() 把后端返回的数据转为 JavaScript 对象。

// { id: 9007199254740996, name: 'Jack', age: 18 }
JSON.parse('{ "id": 9007199254740995, "name": "Jack", "age": 18 }')
复制代码

可以看到,超出安全整数范围的 id 无法精确表示,这个问题并不是 axios 的错。

了解了什么是大整数的概念,接下来的问题是如何解决?

json-bigint 是一个第三方包,它可以帮我们很好的处理这个问题。

使用它的第一步就是把它安装到你的项目中。

npm i json-bigint
复制代码

下面是使用它的一个简单示例。

const jsonStr = '{ "art_id": 1245953273786007552 }'

console.log(JSON.parse(jsonStr)) // 1245953273786007600
// JSON.stringify()

// JSONBig 可以处理数据中超出 JavaScript 安全整数范围的问题
console.log(JSONBig.parse(jsonStr)) // 把 JSON 格式的字符串转为 JavaScript 对象

// 使用的时候需要把 BigNumber 类型的数据转为字符串来使用
console.log(JSONBig.parse(jsonStr).art_id.toString()) // 1245953273786007552

console.log(JSON.stringify(JSONBig.parse(jsonStr)))

console.log(JSONBig.stringify(JSONBig.parse(jsonStr))) // 把 JavaScript 对象 转为 JSON 格式的字符串转
复制代码

1582099315865-5e805425-7abf-4cf2-9df3-acc2ef8f9bb9.png

json-bigint 会把超出 JS 安全整数范围的数字转为一个 BigNumber 类型的对象,对象数据是它内部的一个算法处理之后的,我们要做的就是在使用的时候转为字符串来使用。

通过 Axios 请求得到的数据都是 Axios 处理(JSON.parse)之后的,我们应该在 Axios 执行处理之前手动使用 json-bigint 来解析处理。Axios 提供了自定义处理原始后端返回数据的 API:transformResponse

npm i json-bigint

 /**
 * 封装 axios 请求模块
 */
import axios from "axios"
import store from '@/store'
import JSONbig from 'json-bigint'
const request = axios.create({
  baseURL: "http://toutiao-app.itheima.net/", // 基础路径

// transformResponse 允许自定义原始的响应数据(字符串) 解决超出js安全整数范围
  transformResponse: [function (data) {
    try {
      // 如果转换成功则返回转换的数据结果
      return JSONbig.parse(data);
    } catch (error) {
      // 如果转换失败,则包装为统一数据格式并返回
      return data
    }
  }],
})

export default request
复制代码

扩展:ES2020 BigInt

ES2020 引入了一种新的数据类型 BigInt(大整数),来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。

参考链接:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享