在前端頁面展示資料的時候,通常都需要處理來自後端的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