问题描述
在项目中,文章列表都成功请求到的情况下,通过已有的文章ID对文章内容请求就报了错。
response和console.log时看到的数据不一致
原因
response看到的数据格式是字符串,preview看到的是用了JSON.parse()做了美化的,转换时出现精度丢失;
1.axios内部会自动的对请求来的文章ID通过JSON.parse, 进行转换
2.但是当请求回来的数据是超大整数时,由于JavaScript本身对数字准确表示是有范围的
(-2^53~2^53之间,不含两头)
3.所以转换时已经产生了误差
json-bigint简介
npm i json-bigint
import JSONbig from 'json-bigint'
const str = '{ "id": 1253585734669959168 }'
console.log(JSON.parse(str)) // 1253585734669959200
// 它会把超出 JS 安全整数范围的数字转为一种类型为 BigNumber 的对象
// 我们在使用的时候需要把这个 BigNumber.toString() 就能得到原来正确的数据了
console.log(JSONbig.parse(str))
console.log(JSONbig.parse(str).id.toString()) // 1253585734669959168
const data = JSONbig.parse(str)
console.log(JSON.stringify(data))
console.log(JSONbig.stringify(data))
json-bigint 会把超出 JS安全整数范围的数字转为一个 BigNumber类型的对象,对象数据是它内部的
一个算法处理之后的,我们要做的就是在使用的时候转为字符串来使用。
解决方案
1.不让axios在其内部通过JSON.parse,对数据进行转换
2.导入第三方包’json-bigint’,来替换原始的转换方法,如何配置到项目中:
import axios from 'axios'
import JSONbig from 'json-bigint'
// 创建一个 axios 实例,说白了就是复制了一个 axios
// 我们通过这个实例去发请求,把需要的配置配置给这个实例来处理
const request = axios.create({
baseURL: 'http://ttapi.research.itcast.cn/', // 请求的基础路径
// 定义后端返回的原始数据的处理
// 参数 data 就是后端返回的原始数据(未经处理的 JSON 格式字符串)
transformResponse: [function (data) {
// 后端返回的数据可能不是 JSON 格式字符串
// 如果不是的话,那么 JSONbig.parse 调用就会报错
// 所以我们使用 try-catch 来捕获异常,处理异常的发生
try {
// 如果转换成功,则直接把结果返回
return JSONbig.parse(data)
} catch (err) {
console.log('转换失败', err)
// 如果转换失败了,则进入这里
// 我们在这里把数据原封不动的直接返回给请求使用
return data
}
// axios 默认在内部使用 JSON.parse 来转换处理原始数据
// return JSON.parse(data)
}]
})
// 请求拦截器
request.interceptors.request.use(
// 任何所有请求会经过这里
// config 是当前请求相关的配置信息对象
// config 是可以修改的
function (config) {
const user = JSON.parse(window.localStorage.getItem('user'))
// 如果有登录用户信息,则统一设置 token
if (user) {
config.headers.Authorization = `Bearer ${user.token}`
}
// 然后我们就可以在允许请求出去之前定制统一业务功能处理
// 例如:统一的设置 token
// 当这里 return config 之后请求在会真正的发出去
return config
},
// 请求失败,会经过这里
function (error) {
return Promise.reject(error)
}
)
// 响应拦截器
// 导出请求方法
export default request