Blob vs Base64 — 同一份資料的兩種面貌
在 Web 開發(特別是處理圖片、檔案上傳)中,Blob 與 Base64 是兩個最常見的名詞。簡單來說,它們是 「同一份資料的兩種不同表現形式」:
- Blob (Binary Large Object):電腦看檔案的方式(二進位、原始資料)
- Base64:為了讓人類或特定傳輸協定方便處理而轉成的「字串」(純文字)
**比喻**
想像你打客服電話報訂單編號 A7B3:
- Blob 就像直接快速唸出 「A-7-B-3」。簡短高效,但電話那頭可能聽成「A-7-D-3」或「8-7-B-3」。
- Base64 就像改說 「A-Apple、7、B-Boy、3」。內容變長了,但能確保對方在「只靠聲音」的通道中準確接收,不會出錯。
一、 核心差異比較表
| 特性 | Blob (Binary Large Object) | Base64 (Data URL) |
|---|---|---|
| 本質 | 原始二進制資料 (0 和 1) | 純文字字串 (ASCII) |
| 檔案大小 | 原始大小 (較小) | 變大約 33% (因為編碼膨脹) |
| 主要用途 | 檔案上傳 (FormData)、下載檔案、影片串流 | 嵌入小圖示 (Icon)、存入 localStorage、JSON 傳輸 |
| 記憶體消耗 | 低 (瀏覽器優化) | 高 (需解析巨型字串) |
| 渲染方式 | 需透過 URL.createObjectURL() 轉成網址 | 直接放入 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)組成。在這些二進位數據中,很有可能剛好包含代表 <、" 或 } 的代碼。
> **災難場景**
假設你硬要把一張圖片的二進制資料塞進 HTML 的 src 屬性裡:
<img src="...[圖片二進制資料]..." />如果圖片資料裡剛好有一個 byte 是 0x22 (也就是雙引號 "),瀏覽器會以為屬性結束了,導致後面的資料被當成 HTML 標籤解析,造成網頁結構瞬間瓦解。
2. JSON 的序列化限制
JSON (JavaScript Object Notation) 的標準規範極度嚴格,它只支援以下幾種資料型態:
- 字串 (String)
- 數字 (Number)
- 布林值 (Boolean)
- 陣列 (Array)
- 物件 (Object)
- null
JSON 不支援「Binary」型別。
當你嘗試在 JavaScript 中把一個 Blob 物件轉成 JSON 字串時:
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 二進制資料直接當作文字讀取:
- 會出現大量的 亂碼
- 會出現 控制字元(如
NULLbyte,\0),這在許多程式語言中代表「字串結束」,導致資料讀取只到一半就被截斷
三、 那我們該怎麼辦?
因為「水(Blob)」不能直接裝進「紙袋(HTML/JSON)」裡,我們有兩種標準做法:
方法 A:把水結成冰(轉成 Base64)
把二進制資料編碼成只有 a-z、A-Z、0-9、+、/ 組成的安全字串。
- 優點:可以直接放進 JSON、CSS (
background-image: url(...)) 或 HTML 裡 - 缺點:體積變大 33%,解析耗效能
方法 B:給水一個門牌號碼(Blob URL)
不把資料放進 HTML,而是產生一個連結 blob:http://localhost/...。
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)。
const url = URL.createObjectURL(file);
imageElement.src = url;- 原因:這是瀏覽器內部的指針,幾乎不消耗效能,瞬間產生。Base64 轉換大圖時會造成 UI 卡頓
- 注意:用完記得釋放
URL.revokeObjectURL(url)
如果是「極小的圖示」:使用 Base64
- 原因:如果圖片只有 1-2KB,為了省去一次 HTTP Request,可以直接將 Base64 寫死在 CSS 或 HTML 裡
總結
| 情境 | 推薦方案 | 理由 |
|---|---|---|
| 檔案上傳 | Blob + FormData | 傳輸量小、伺服器無需解碼 |
| 圖片預覽 | Blob URL | 效能極佳、瞬間產生 |
| 存入 localStorage | Base64 | localStorage 只能存字串 |
| 極小圖示 (< 2KB) | Base64 | 省一次 HTTP Request |
| JSON API 傳輸圖片 | Base64 或改用 FormData | JSON 不支援 Binary |
- Blob 是為了 效能與傳輸(給機器與網路用的)
- Base64 是為了 方便嵌入與文字化(給 HTML/CSS 或 JSON 用的)