el-upload上傳文件時返回的字符串異常

問題描述

在使用element-ui的文件上傳插件進行資源上傳時,後端所返回的數據是一個形如“3297799991516386308”的字符串,也就是資源id。

但是在on-success回調函數中得到的response卻是3297800280615081000。顯然這個結果並不是隨機生成的,因爲兩者有着明顯的相似性。並且這個response並不是字符串,而是一個數字。將這個id傳到後臺時就會出現與後臺資源id不匹配的情況。

問題跟蹤

從返回的結果可以推斷,我們傳入的on-success函數已經成功調用了。打開瀏覽器的network查看該請求,發現請求返回的是正確的id。於是問題應該定位到el-upload這個插件本身。

打開node_modules中element-ui文件夾,找到upload組件,發現它是這樣調用我們傳入的on-success函數的(具體的跟蹤過程略過):

xhr.onload = function onload() {
    if (xhr.status < 200 || xhr.status >= 300) {
      return option.onError(getError(action, option, xhr));
    }

    option.onSuccess(getBody(xhr));
  };

在瀏覽器中全局搜索option.onSuccess,然後格式化並在這一行打斷點,發現xhr中的response和responseText均爲正確的字符串id,但是getBody(xhr)的結果卻是錯的,這就表示getBody在解析返回結果的時候出錯了。於是繼續在getBody函數中打斷點:

function getBody(xhr) {
  const text = xhr.responseText || xhr.response;
  if (!text) {
    return text;
  }

  try {
    return JSON.parse(text);
  } catch (e) {
    return text;
  }
}

斷點走到return JSON.parse(text)時就出了問題,我們這裏傳入的是正確的字符串“3297799991516386308”,解析的結果卻是3297800280615081000。

我們先來看這裏的邏輯,它首先試圖用JSON.parse來解析返回結果,如果不是標準的JSON字符串,那麼這裏就會異常,框架捕獲到異常後就會直接把原始的字符串返回回來。

這個邏輯看似並沒有問題,假如返回的是普通字符串,如"abc",進行parse時就會出現異常,然後正確捕獲並返回原始字符串。但是如果字符串的每個字符都是阿拉伯數字,問題就來了,瀏覽器執行parse時不會拋出異常,而是將其轉化爲數字,比如:

JSON.parse("123") => 123

按理來說,雖然返回的結果是數字,但是隻需要用toString()轉爲字符串,仍然能得到原始字符串,不會出現上述兩者不一致的情況。

出現這個問題的原因就是這個數字太大了,超出了JavaScript所能表示的數字的最大範圍,所以瀏覽器只能用0來填充最後幾位。於是原始的阿拉伯數字構成的字符串就被解析成了錯誤的數值。即“3297799991516386308”被解析爲了3297800280615081000。

問題解決

定位到問題之後,解決就變得非常簡單,只需要避開直接返回過長的阿拉伯字符串即可。比如可以讓後臺返回對象格式的數據,或者不要使用純數字id,或者縮短id的長度,都可以解決這個問題。

說到底,這個問題算是el-upload這個插件的bug,它沒有考慮到返回的數據可能是很長的數字字符串這種情況。要解決這類問題,不要怕打開插件源碼,查看插件的實現邏輯,因爲插件很難保證不會存在bug。這裏希望給遇到同樣問題的同學一個參考。

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