[小菜一碟] 使用 jQuery $.ajax 下載圖片等二進位資料

之前有一個案子的使用者有一個特別的要求,因為在網頁上瀏覽的圖片大小稍微大了一點,在行動裝置上網路不穩定的時候,會載入比較久的時間,所以使用者就想說能不能在圖片顯示前,先顯示一個 Loading 的畫面,等待圖片下載完成之後再顯示出來?

一般來說,網頁要顯示圖片,通常就是指定 <img> 的 src 屬性值就可以了,但是要滿足前述使用者所提出的要求,我們就得在背景等待圖片下載完成,才將圖片顯示出來,所以我打算用 CSS 來顯示 Loading 效果,用 jQuery 的 $.ajax() 非同步下載圖片,圖片下載完成後,關閉 CSS Loading 效果,然後將下載下來的二進位圖片檔塞進 <img> 的 src 顯示出來。

CSS Loading 效果

由於我對 CSS 只停留在新手村的程度,所以 CSS Loading 效果我只有能力找網路上現成的來用,https://tobiasahlin.com/spinkit/ 這個網頁收錄幾種 CSS Loading 效果,我挑其中一個來用。

<!-- HTML -->
<div class="spinner"></div>

<!-- CSS -->
.spinner {
    width: 40px;
    height: 40px;
    background-color: #333;

    margin: 100px auto;
    -webkit-animation: sk-rotateplane 1.2s infinite ease-in-out;
    animation: sk-rotateplane 1.2s infinite ease-in-out;
}

@@-webkit-keyframes sk-rotateplane {
0% { -webkit-transform: perspective(120px) }
50% { -webkit-transform: perspective(120px) rotateY(180deg) }
100% { -webkit-transform: perspective(120px) rotateY(180deg)  rotateX(180deg) }
}

@@keyframes sk-rotateplane {
0% { 
    transform: perspective(120px) rotateX(0deg) rotateY(0deg);
    -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg) 
} 50% { 
      transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
      -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg) 
  } 100% { 
        transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
        -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
    }
}

$.ajax() 下載圖片

如果我們直接用 $.ajax() 發送 HTTP Request 去 GET 一張圖片,是無法取得正確結果的,我們會收到一堆亂碼,原因是因為 $.ajax() 預設沒有針對二進位資料進行相應的處理,一律視為文字資料。

那該怎麼辦? 我們要了解 $.ajax() 其實是 XMLHttpRequest 的封裝,而 XMLHttpRequest 回傳的資料類型是由 responseType 這個屬性來決定的,預設值是空字串,等同於是 text,我們只要將其值改為 blob,收到的回傳結果就會是 Blob 物件

想知道 XMLHttpRequest 的 responseType 還支援哪些資料類型,可以參考 MDN 的說明

要在 $.ajax() 調整 XMLHttpRequest 的 responseType 屬性值,必須在 xhrFields 設定裡面,指定 responseType 的值。

接下來事情就變得簡單了,只剩下將圖片的 Blob 物件塞給 <img> 的 src 屬性就搞定了,我這邊選用 Data URL 的方式,使用 FileReaderreadAsDataURL() 方法來處理。

另一種方式是使用 Object URL 來處理,也是可以的。

下載其他二進位資料

我們下載的二進位資料是圖片的話,有 <img> 可以將其顯示出來,但是如果我們下載的二進位資料是 .pdf、.docx、.xlsx、...等非圖片的資料,一般處理的方式是另存新檔,下面我們就來撰寫用 $.ajax() 將二進位資料下載下來之後,觸發彈跳出另存新檔視窗的程式碼。

我們利用點擊超連結觸發另存新檔的方式來做,關鍵的地方在於超連結需要指定 download 屬性值,給它一個另存新檔的檔案名稱。

同場加映

如果我們很不幸運,遇到一個菜鳥後端工程師,用 text/plain 傳 JSON 物件到前端給我們,調整 XMLHttpRequest 的 responseType 為 json,也可以解決資料類型不對的問題。

在我剛學習網頁程式設計的那個年代,還沒有 XMLHttpRequest,網頁的互動也比較死板一點,跟現在差很多,在未來 HTML 的 Web APIs 勢必會日臻豐富,有一個網站 WHAT WEB CAN DO TODAY? 收錄了到目前為止,我們可以在 Web 應用程式上做到的事情,每一個 Feature 點進去還提供了範例程式碼,這都是在過去很難想像的,以上用 jQuery 的 $.ajax() 下載二進位資料的方式分享給大家,順道也分享一些額外的資訊,希望對大家有一點幫助。

參考資料

相關資源

C# 指南
ASP.NET 教學
ASP.NET MVC 指引
Azure SQL Database 教學
SQL Server 教學
Xamarin.Forms 教學