跳至主要內容
Skip to content

Blob vs Base64 — 同一份資料的兩種面貌

在 Web 開發(特別是處理圖片、檔案上傳)中,Blob 與 Base64 是兩個最常見的名詞。簡單來說,它們是 「同一份資料的兩種不同表現形式」

  • Blob (Binary Large Object):電腦看檔案的方式(二進位、原始資料)
  • Base64:為了讓人類或特定傳輸協定方便處理而轉成的「字串」(純文字)

TIP

比喻 想像你打客服電話報訂單編號 A7B3

  • Blob 就像直接快速唸出 「A-7-B-3」。簡短高效,但電話那頭可能聽成「A-7-D-3」或「8-7-B-3」。
  • Base64 就像改說 「A-Apple、7、B-Boy、3」。內容變長了,但能確保對方在「只靠聲音」的通道中準確接收,不會出錯。

先講結論

你想做的事推薦做法原因
上傳檔案FormData.append("file", file)保留原始二進位,傳輸量小,後端好接
顯示本機預覽URL.createObjectURL(file)不需要把整個檔案轉成字串
把小圖示寫進 CSS/HTMLBase64 Data URL可省一次請求,但只適合小資源
把圖片放進 JSON小圖可 Base64;大圖改 multipartJSON 沒有 Binary 型別
長期保存圖片上傳到後端或存 IndexedDBBlob URL 不是永久網址

一、 核心差異比較表

特性Blob (Binary Large Object)Base64 / Data URL
本質原始二進制資料可放進文字通道的編碼字串
大小接近原始檔案大小通常約膨脹 33%,Data URL 前綴還會再多一點
主要用途檔案上傳、下載、影片串流、本機預覽小圖示內嵌、JSON 傳小型檔案、文字欄位保存
記憶體消耗瀏覽器可用原生檔案物件處理大字串解析、複製與塞入 DOM 都比較吃資源
渲染方式透過 Blob URL 或直接交給 API可直接放入 src,例如 data:image/png;base64,...

二、 為什麼 Blob 無法直接塞進 HTML/JSON?

這是因為 Blob 是「二進位世界」的居民,而 HTML/CSS/JSON 是「文字世界」的產物。如果不經過轉換,直接把 Blob 硬塞進去,會發生三個致命問題:

1. 語法崩壞 (Syntax Breaking)

HTML、CSS 和 JSON 都是基於 純文字 (Text-based) 的格式,它們依賴特定的「特殊符號」來定義結構:

  • HTML 依賴 <>
  • CSS 依賴 {}
  • JSON 依賴 " (雙引號) 和 , (逗號)

Blob (二進制資料) 是由 0 到 255 的位元組(Bytes)組成。在這些二進位數據中,很有可能剛好包含代表 <"} 的代碼。

WARNING

災難場景 假設你硬要把一張圖片的二進制資料塞進 HTML 的 src 屬性裡:

html
<img src="...[圖片二進制資料]..." />

如果圖片資料裡剛好有一個 byte 是 0x22 (也就是雙引號 "),瀏覽器會以為屬性結束了,導致後面的資料被當成 HTML 標籤解析,造成網頁結構瞬間瓦解。

2. JSON 的序列化限制

JSON (JavaScript Object Notation) 的標準規範極度嚴格,它只支援以下幾種資料型態:

  • 字串 (String)
  • 數字 (Number)
  • 布林值 (Boolean)
  • 陣列 (Array)
  • 物件 (Object)
  • null

JSON 不支援「Binary」型別。

當你嘗試在 JavaScript 中把一個 Blob 物件轉成 JSON 字串時:

javascript
const blob = new Blob(["Hello"], { type: "text/plain" });
const json = JSON.stringify({ file: blob });

console.log(json);
// 輸出結果: {"file":{}}

結果是空的! 因為 Blob 是一個指向記憶體(或硬碟)的「複雜物件參照」,它不是純資料值。JSON.stringify 不知道該如何把這個「記憶體指針」變成文字,所以直接忽略它。

3. 傳輸協定的字元編碼問題

HTML/CSS/JSON 通常使用 UTF-8 編碼來儲存和傳輸。UTF-8 是針對文字設計的編碼,並非所有的二進位 byte 序列都是合法的 UTF-8 字元。

如果你把原始的 Blob 二進制資料直接當作文字讀取:

  1. 會出現大量的 亂碼
  2. 會出現 控制字元(如 NULL byte, \0)。JavaScript 字串本身可以包含 \0,但許多底層語言、舊系統或文字處理流程會把它視為特殊字元,可能造成資料解析錯誤或截斷

三、 那我們該怎麼辦?

因為「水(Blob)」不能直接裝進「紙袋(HTML/JSON)」裡,我們有兩種標準做法:

方法 A:把水結成冰(轉成 Base64)

把二進制資料編碼成文字字串。標準 Base64 主要由 a-zA-Z0-9+/ 組成,尾端可能有 = 補齊;URL-safe Base64 則常把 +/ 換成 -_

  • 優點:可以直接放進 JSON、CSS (background-image: url(...)) 或 HTML 裡
  • 缺點:體積變大 33%,解析耗效能

方法 B:給水一個門牌號碼(Blob URL)

不把資料放進 HTML,而是產生一個連結 blob:http://localhost/...

javascript
const url = URL.createObjectURL(file);
// url = "blob:http://localhost:3000/550e8400-e29b-41d4-a716-446655440000"
  • 原理:告訴 HTML:「圖片不在這裡,請去記憶體的這個地址找」
  • 優點:效能極佳,HTML 依然保持乾淨的文字格式
  • 限制:它不是可持久化網址,生命週期受建立它的瀏覽器文件管理,無法存進 JSON 傳給後端後再使用

四、 實戰建議:該選哪一個?

如果是「檔案上傳」:使用 Blob

當你要把使用者選的照片傳給後端 API 時,絕對建議使用 Blob

  • 原因:透過 FormData 傳送 Blob 是標準的 multipart/form-data 格式,伺服器不需要額外解碼 Base64,且傳輸量小 33%

如果是「圖片預覽」:使用 Blob URL

早期大家習慣轉 Base64 做預覽,但現在更推薦使用 Blob URL (Object URL)

javascript
const url = URL.createObjectURL(file);
imageElement.src = url;
  • 原因:這是瀏覽器內部的指針,幾乎不消耗效能,瞬間產生。Base64 轉換大圖時會造成 UI 卡頓
  • 注意:用完記得釋放 URL.revokeObjectURL(url)

Blob URL 適合「這個頁面目前要預覽」的情境。它不適合存進資料庫、傳給後端、貼給別人或期待重新整理後仍可使用。

如果是「極小的圖示」:使用 Base64

  • 原因:如果圖片只有 1-2KB,為了省去一次 HTTP Request,可以直接將 Base64 寫死在 CSS 或 HTML 裡

總結

情境推薦方案理由
檔案上傳Blob + FormData傳輸量小、伺服器無需解碼
圖片預覽Blob URL效能極佳、瞬間產生
存入 localStorageBase64localStorage 只能存字串
極小圖示 (< 2KB)Base64省一次 HTTP Request
JSON API 傳輸圖片Base64 或改用 FormDataJSON 不支援 Binary
  • Blob 是為了 效能與傳輸(給機器與網路用的)
  • Base64 是為了 方便嵌入與文字化(給 HTML/CSS 或 JSON 用的)

常見誤解

誤解正確理解
Blob 不能顯示圖片Blob 可以顯示,但通常要先建立 Blob URL
Base64 比 Blob 更安全Base64 只是編碼,不是加密,也不會自動消毒內容
Blob URL 是永久連結Blob URL 只在建立它的瀏覽器環境中有效
JSON 可以直接放 BlobJSON.stringify(blob) 不會序列化檔案內容

練習:驗證你真的懂了

練習 1:JSON 真的放不進 Blob 嗎?

先猜下面會輸出什麼,再貼到瀏覽器 Console 執行:

javascript
const blob = new Blob(["Hello"], { type: "text/plain" });
console.log(JSON.stringify({ file: blob }));
console.log(blob.size, blob.type);
看答案

JSON.stringify({ file: blob }) 會得到 {"file":{}}。Blob 本身仍然有 sizetype,但 JSON 不知道如何把檔案內容序列化成文字欄位。

練習 2:Blob URL 是永久網址嗎?

跑這段程式:

javascript
const blob = new Blob(["Hello Blob URL"], { type: "text/plain" });
const url = URL.createObjectURL(blob);

console.log(url);
URL.revokeObjectURL(url);

觀察 url 長什麼樣子。它看起來像網址,但它只是在目前瀏覽器環境中指向一份 Blob 的臨時參照。

自我檢查

  • 如果要上傳 8MB 圖片,會用 Base64 還是 FormData
  • Blob URL 適合存進資料庫嗎?
  • Base64 是加密嗎?
  • JSON.stringify(blob) 會包含檔案內容嗎?

← 返回專題首頁 | 下一章:從 0/1 到 0-255 →