HTML Files指定後上傳前,被使用者編輯儲存後引發咬檔錯誤

最近處理一則檔案上傳的需求,發現了一個問題,就是當使用者針對HTML的input type="file"進行指定檔案後,然後又把檔案開啟來編輯與儲存,然後再去點選上傳按鈕來進行檔案上傳(或其他關於檔案的後續操作),這時候Chrome瀏覽器會給你一組神秘的報錯,且這個錯誤細節不好攔截。

經過千辛萬苦後,終於找到翻出這個錯誤的關鍵字:

DOMException: The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.

DOM例外情況:由於在獲取文件引用後發生的權限問題,通常導致無法讀取請求的文件。

白話的說法,就是:使用者把檔案變更了,我的讀取權限被搶走了。

針對瀏覽器對於讀取權限被搶走,進行錯誤攔截

總要跟使用者明白的說明是怎樣的錯誤吧,不然又要被無端怪罪豈不冤枉?過程需要透過Javascript的File API之FileReader物件。但這個物件只能用非同步(asynchronously)方式讀取儲存在用戶端的檔案,所以如果要偵測到瀏覽器讀取檔案的權限被搶走,就顯示警告並停止,又得繞路把非同步改成同步,只能說是非常的脫褲子放屁。

以下是解法:

function CheckFileState() {
  return new Promise((resolve, reject) => {
    let oFile = 修改你要偵測的Selector;
    if (!oFile) {
      reject("上傳檔案前請先指定檔案。");
    }
    let oReader = new FileReader();
    oReader.onload = function () {
      resolve();
    };
    oReader.onerror = function (e) {
      //如果要上面文章中那串錯誤的關鍵字,可以把`e.target.result`拿出來看
      reject("偵測到檔案在指定後被修改並儲存,請重新指定。");
    };
    oReader.readAsArrayBuffer(oFile);
  });
}

透過Promise的寫法後,就可以放心開始使用了。

CheckFileState()
  .then(() => {
    return UploadFiles();
  })
  .then((oData) => {
    console.log(oData);
  })
  .catch(function (cMessage) {
    console.log(cMessage);
    //這邊可以順便寫一下把檔案或表單reset的程式碼
  });

感想

瀏覽器彈出一下官方標準錯誤,提示給使用者看是會死嗎?

Chrome Edge Chromium Browser Html Files Selected Chosen Upload Before After FileChanged FileEdited FileModified