Jison解決JS處理後端返回的Long型數據精度丟失問題

在前端頁面展示數據的時候,通常都需要處理來自後端的json數據。通常這個過程都是非常簡單的,比如通過jQuery的ajax。但是如果服務器傳來的json中包含一個很大的整數,如 { “id”: 296675198462066688 } ,那麼接受後會發現變成了 { id: 296675198462066700 } 。

簡單的解決方法,讓後端傳給你string類型
但是後端的人會說:你們前端怎麼顯示個long類型都搞不定!

問題原因

js是弱類型語言,所有的數字類型統稱爲Number類型,不區分int、long、double等。而Number是根據IEEE 754標準中的double來實現的,即所有的Number類型都是64位雙精度實型。segmentfault上提供了一個對 IEEE 574標準
非常友好的講解,這裏不再講述。

js內置有32位整數,而number類型的安全整數是53位。如果超過53位的,你不能用json傳遞,需要用其他數據類型,比如字符串,或拆分成兩個數據字段。

解決思路

GitHub開源項目—— Jison,號稱“bison in javascript”,通過它可以實現對後端返回數據的重新定義一個自己的json parser。

在拿到接口請求返回的數據的時候,不用json自帶的那個parse方法,而是通過自己定義了一個json轉換方法,然後再response給前端,這樣一來前端拿到的數據就是一個處理過的json數據。

自定義 json parser

首先使用Node安裝Jison

npm install jison -g

同時在 lib 目錄下提供了 cli.js 來生成我們想自定義的parser。參數有兩個(詳見cli.js代碼), cli.js grammaFile lexFile ,grammaFile是語法文件,lexFile是詞表文件。

下面就是怎麼寫這兩個文件了,可以通過 文檔 來學習一下這類文件的語法。如果不想這麼麻煩,還可以在jison作者的另一個項目—— jsonlint 裏面找到,在github中該項目的src目錄下提供了jsonlint.y(grammaFile)和jsonlint.l(lexFile)兩個文件。使用這兩個文件可以直接生成jsonlint.js,放到網頁中當json parser來使用。

這裏我們以修改jsonlint裏面的兩個文件爲例生成我們所需要的json parse

我們的目的是讓一些會丟失精度的整數被保留下來,最好的方法是:當整數超過了安全範圍的時候,使用字符串表示。我們可以通過修改jsonlint.y來達到這個目的。

原本對JSONNumber的定義是

JSONNumber
    : NUMBER
        {$$ = Number(yytext);}
    ;

在這裏yytext是要進行解析的原始數據,$$是結果。我們可以修改成

JSONNumber
    : NUMBER
        {$$ = yytext == String(Number(yytext))? Number(yytext): yytext;}
    ;

==> 生成我們要的 jsonlint.js:

git clone git://github.com/zaach/jsonlint.git
cd src
jison jsonlint.y jsonlint.l

引入至項目

這裏以Vue項目爲例:

1、將自定義的 jsonlint.js 放到 static 目錄下

static.jpg

2、在 index.html 中引入

<script src="./static/jsonlint/jsonlint.js"></script>

3、在我們請求的返回數據中,做一層攔截轉換

此處以 axios 的實現方法爲例:

// transformResponse 選項允許我們在數據傳送到 `then/catch` 方法之前對數據進行改動
axios.defaults.transformResponse = [
  function(data) {
    return jsonlint.parse(data)
  }
]

總結

綜上,通過自定義JSON轉化避免long類型數據溢出,可以實現long類型數據在前端正常顯示。

注意: 這個方法的確可以實現前端拿到的數據不出現精度丟失問題,但是再瀏覽器中的Preview上查看數據還是一個丟失的錯誤數據,這個是因爲瀏覽器它用的還是自己原始的那個json parse方法。

後記:
小夥伴們,如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果覺得本文還不錯,記得點個贊哦!
本文首發地址爲: Vae’s Blog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章