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 目錄下

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