Base64 是什麼?

Base64 是一種將二進位資料轉換為純文字的編碼方式。它使用 64 個可列印的 ASCII 字元(A-Z、a-z、0-9、+、/)來表示任意二進位資料,讓原本無法在文字環境中傳輸的二進位內容(如圖片、檔案),能安全地以文字形式傳送。

Base64 的名稱來自它使用的 64 個字元。每 3 個位元組(24 bits)的原始資料會被編碼成 4 個 Base64 字元(每個字元代表 6 bits),因此編碼後的資料大小會增加約 33%。

Base64 不是加密!它只是一種編碼方式,任何人都可以輕易解碼。不要用 Base64 來「保護」敏感資料。

Base64 的歷史背景

Base64 編碼的起源可以追溯到早期電子郵件系統的設計。1980 年代,電子郵件協議(SMTP)只能處理 7-bit ASCII 文字,無法直接傳送二進位檔案。為了解決這個限制,RFC 2045 定義了 MIME(Multipurpose Internet Mail Extensions)標準,其中包含 Base64 編碼方式,讓圖片、PDF、壓縮檔等二進位內容能透過純文字的電子郵件系統傳遞。

時至今日,Base64 的應用早已超越電子郵件,廣泛用於 Web 開發、API 認證、資料傳輸等各個層面。對於前端開發者和後端工程師而言,理解 Base64 編碼解碼的原理和正確使用方式,是不可或缺的基礎技能。

Base64 的編碼原理

字元對照表

Base64 使用以下 64 個字元進行編碼:

索引  字元    索引  字元    索引  字元    索引  字元
 0    A       16    Q       32    g       48    w
 1    B       17    R       33    h       49    x
 2    C       18    S       34    i       50    y
 3    D       19    T       35    j       51    z
 4    E       20    U       36    k       52    0
 5    F       21    V       37    l       53    1
 ...
63    /       填充字元: =

這 64 個字元的選擇並非隨意:它們都是 ASCII 可列印字元,在各種作業系統、傳輸協議和程式語言中都能安全處理,不會被誤解為控制字元或特殊符號。

編碼步驟詳解

以字串 "Hi" 為例,完整的編碼過程如下:

  1. 轉換為 ASCII 值:H = 72, i = 105
  2. 轉換為二進位:01001000 01101001
  3. 補零至 24 bits 的倍數:01001000 01101001 00000000
  4. 每 6 bits 分組:010010 000110 100100 000000
  5. 對照表轉換:S G k A
  6. 加填充符號SGk=(原始資料 2 bytes,需補 1 個 =

填充規則

填充符號 = 的目的是讓 Base64 編碼後的字串長度始終為 4 的倍數,這對解碼器而言是重要的格式保證:

  • 原始資料 bytes 數 % 3 = 0:不需填充
  • 原始資料 bytes 數 % 3 = 1:填充 ==
  • 原始資料 bytes 數 % 3 = 2:填充 =

編碼效率分析

Base64 編碼會增加約 33% 的資料大小。這是因為每 3 個原始位元組(24 bits)被編碼為 4 個 Base64 字元(32 bits)。如果使用 MIME 格式(每 76 字元換行),額外的換行符會再增加約 2-3% 的大小。

以實際數據為例: - 1 KB 的原始資料 → 約 1.37 KB 的 Base64 文字 - 100 KB 的圖片 → 約 133 KB 的 Base64 字串 - 1 MB 的檔案 → 約 1.33 MB 的 Base64 文字

這個大小增幅在處理小型資源時可以接受,但在處理大型檔案時就需要謹慎考量。

實際應用場景

1. Data URI — 圖片嵌入 HTML/CSS

Data URI 是 Base64 在前端開發中最常見的應用之一。將小型圖片直接嵌入 HTML 或 CSS 中,可以減少 HTTP 請求數,提升頁面初次載入速度:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" alt="小圖示">

在 CSS 中:

.icon {
  background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0...');
}

Data URI 的最佳實踐:

檔案大小 建議做法 原因
< 2 KB 強烈建議使用 Data URI 省掉的 HTTP 請求比大小增幅更划算
2-5 KB 可以使用 Data URI 適合圖示、小型裝飾圖
5-10 KB 視情況決定 需考量 HTML 檔案大小影響
> 10 KB 不建議使用 Data URI HTML 過大,且無法獨立快取

值得注意的是,嵌入在 HTML 或 CSS 中的 Base64 圖片無法被瀏覽器獨立快取。如果同一張圖片在多個頁面使用,每次頁面載入都要重新下載整個 Base64 字串。因此,重複使用的圖片建議採用獨立檔案搭配 CDN 快取。

2. API 認證 — Basic Authentication

HTTP Basic Authentication 使用 Base64 編碼傳送帳號密碼。這是最簡單的 HTTP 認證機制:

Authorization: Basic dXNlcjpwYXNzd29yZA==

其中 dXNlcjpwYXNzd29yZA== 就是 user:password 的 Base64 編碼。認證流程如下:

  1. 客戶端將 username:password 組合成一個字串
  2. 對該字串進行 Base64 編碼
  3. 在 HTTP Header 中加入 Authorization: Basic <編碼結果>
  4. 伺服器收到後解碼驗證

安全注意事項: Basic Auth 必須搭配 HTTPS 使用。Base64 只是編碼,不是加密,任何攔截到 HTTP 請求的人都能輕易解碼取得帳號密碼。在正式環境中,建議使用 OAuth 2.0 或 API Key + HMAC 簽名等更安全的認證機制。

3. JWT Token(JSON Web Token)

JWT 是現代 Web 應用最常用的身份驗證機制之一。它的三個部分(Header、Payload、Signature)都使用 Base64URL 編碼:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Base64URL 與標準 Base64 的差異在於:將 + 換成 -/ 換成 _、去除 = 填充。這是因為 +/= 在 URL 中都有特殊意義,直接使用會造成解析錯誤。

JWT 的解碼對於除錯非常實用。你可以使用 Super Tools 的 Base64 編碼解碼工具 來快速解碼 JWT 的 Header 和 Payload,查看其中包含的使用者資訊和 Token 過期時間。

4. Email 附件 — MIME 編碼

電子郵件的 MIME 標準使用 Base64 編碼傳送二進位附件。由於 SMTP 協議只支援 7-bit ASCII,所有非文字內容都必須先 Base64 編碼:

Content-Type: application/pdf
Content-Transfer-Encoding: base64

JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlIC9DYXRh...

MIME Base64 格式的特殊之處在於每 76 個字元會插入一個換行符(CRLF),這是早期郵件伺服器對單行長度的限制。現代的 Base64 實作通常不需要換行,除非明確處理電子郵件格式。

5. 嵌入字型與 SVG 資源

Web 開發中,小型字型檔案和 SVG 圖示可以 Base64 編碼後嵌入 CSS,減少額外的網路請求:

@font-face {
  font-family: 'CustomIcon';
  src: url('data:font/woff2;base64,d09GMgABAAAAAA...') format('woff2');
}

對於 SVG 圖示系統,Base64 嵌入特別適合只有少量圖示的情況。若圖示數量超過 10 個,建議改用 SVG sprite 或 icon font 方案。

6. 前端檔案上傳預覽

在使用者選擇圖片上傳前,前端常用 FileReader API 將圖片讀取為 Base64 Data URI 進行預覽:

const reader = new FileReader();
reader.onload = (e) => {
  document.getElementById('preview').src = e.target.result;
};
reader.readAsDataURL(file); // 讀取為 Base64 Data URI

這個技巧讓使用者在上傳前就能看到圖片預覽,不需要先將圖片傳到伺服器。

程式語言實作範例

JavaScript(瀏覽器端)

// 基本編碼
const encoded = btoa('Hello, World!');
console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="

// 基本解碼
const decoded = atob('SGVsbG8sIFdvcmxkIQ==');
console.log(decoded); // "Hello, World!"

// 處理 Unicode(中文等)— btoa 不支援非 ASCII 字元
function utf8ToBase64(str) {
  return btoa(encodeURIComponent(str).replace(
    /%([0-9A-F]{2})/g,
    (_, p1) => String.fromCharCode(parseInt(p1, 16))
  ));
}

function base64ToUtf8(b64) {
  return decodeURIComponent(
    atob(b64).split('').map(
      c => '%' + c.charCodeAt(0).toString(16).padStart(2, '0')
    ).join('')
  );
}

// 使用範例
const chineseEncoded = utf8ToBase64('你好世界');
console.log(chineseEncoded); // "5L2g5aW95LiW55WM"
console.log(base64ToUtf8(chineseEncoded)); // "你好世界"

常見錯誤: 直接對中文字串使用 btoa() 會拋出 InvalidCharacterError,因為 btoa() 只接受 Latin-1 字元。務必先使用 encodeURIComponent 轉換為 UTF-8 編碼的 ASCII 字串。

Python

import base64

# 文字編碼
text = "Hello, World!"
encoded = base64.b64encode(text.encode('utf-8')).decode('ascii')
print(encoded)  # SGVsbG8sIFdvcmxkIQ==

# 文字解碼
decoded = base64.b64decode(encoded).decode('utf-8')
print(decoded)  # Hello, World!

# 圖片轉 Base64(生成 Data URI)
with open('logo.png', 'rb') as f:
    img_base64 = base64.b64encode(f.read()).decode('ascii')
    data_uri = f'data:image/png;base64,{img_base64}'

# Base64URL 編碼(用於 JWT 等 URL 安全場景)
url_safe = base64.urlsafe_b64encode(b'Hello!').decode()
print(url_safe)  # SGVsbG8h

# 中文字串處理
chinese_text = "你好世界"
chinese_encoded = base64.b64encode(chinese_text.encode('utf-8')).decode('ascii')
print(chinese_encoded)  # 5L2g5aW95LiW55WM

Node.js

// 文字編碼
const encoded = Buffer.from('Hello, World!').toString('base64');

// 文字解碼
const decoded = Buffer.from(encoded, 'base64').toString('utf-8');

// 讀取檔案轉 Base64
const fs = require('fs');
const fileBase64 = fs.readFileSync('image.png').toString('base64');

// Base64URL 編碼(Node.js 原生支援)
const urlSafe = Buffer.from('Hello!').toString('base64url');

// 串流處理大型檔案(避免記憶體溢出)
const { Transform } = require('stream');
const readStream = fs.createReadStream('large-file.pdf');
const base64Stream = readStream.pipe(new Transform({
  transform(chunk, encoding, callback) {
    callback(null, chunk.toString('base64'));
  }
}));

命令列工具

在 Linux/macOS 終端機中也能直接進行 Base64 操作:

# 編碼字串
echo -n "Hello" | base64
# SGVsbG8=

# 解碼字串
echo "SGVsbG8=" | base64 --decode
# Hello

# 編碼檔案
base64 image.png > image.b64

# 解碼檔案
base64 --decode image.b64 > image_restored.png

Base64 變體比較

不同的應用場景使用不同的 Base64 變體:

變體 字元差異 換行 用途
標準 Base64(RFC 4648) +, /, = 一般用途
Base64URL(RFC 4648 §5) -, _, 無填充 URL、JWT、檔案名稱
MIME Base64(RFC 2045) +, /, = 每 76 字元 Email 附件
Base32 A-Z, 2-7 不分大小寫的場景

選擇變體時的原則:如果編碼後的字串會出現在 URL 中(query string、路徑參數),必須使用 Base64URL;如果用於電子郵件,使用 MIME Base64;其餘情況使用標準 Base64 即可。

效能考量與最佳實踐

何時該用 Base64

  • 小型圖示和裝飾圖(< 5KB)嵌入 HTML/CSS
  • API 認證標頭中的憑證傳輸
  • 文字環境中傳送少量二進位資料
  • 前端檔案預覽功能

何時不該用 Base64

  • 大型檔案傳輸:33% 的大小膨脹會顯著增加網路流量和記憶體使用
  • 資料加密:Base64 不提供任何安全性保護
  • 頻繁存取的靜態資源:獨立檔案可被瀏覽器快取,Base64 嵌入則不行
  • 資料庫儲存:二進位格式(BLOB)或檔案系統儲存更有效率

效能最佳化建議

  1. 設定合理的大小閾值:自動化建構工具中設定 5KB 以下的圖片自動轉 Base64
  2. 使用串流處理:處理大型檔案時避免一次讀入記憶體
  3. 考慮 gzip 壓縮:Base64 文字的 gzip 壓縮效果通常不如原始二進位檔案
  4. 善用建構工具:Webpack、Vite 等工具可自動處理小圖片的 Base64 內嵌

常見錯誤與除錯

中文亂碼問題

最常見的錯誤是忘記處理字元編碼。Base64 編碼的是位元組序列,不是字元。中文字串必須先轉為 UTF-8 位元組再編碼:

# 錯誤:直接編碼可能產生亂碼或錯誤
# 正確:先指定 UTF-8 編碼
encoded = base64.b64encode("你好".encode('utf-8'))

換行符干擾

某些系統產生的 Base64 字串包含換行符(MIME 格式),在非 MIME 場景使用時需要先移除:

const cleanBase64 = dirtyBase64.replace(/[\r\n]/g, '');

填充符號缺失

某些 API 回傳的 Base64 字串省略了結尾的 = 填充。解碼前可以自動補上:

function addPadding(base64) {
  const pad = base64.length % 4;
  if (pad === 2) return base64 + '==';
  if (pad === 3) return base64 + '=';
  return base64;
}

常見問題 FAQ

Q1:Base64 編碼和加密有什麼不同?

Base64 是一種編碼方式,目的是將二進位資料轉換為安全的文字格式,任何人都可以解碼。加密(如 AES、RSA)是為了保護資料安全,需要密鑰才能解密。在傳輸敏感資訊時,應使用 HTTPS + 加密演算法,而非單純的 Base64 編碼。

Q2:為什麼 Base64 編碼後資料會變大 33%?

因為 Base64 用 4 個字元(32 bits)來表示 3 個原始位元組(24 bits),資料的表示效率從 8 bits/字元降低到 6 bits/字元。這是文字安全傳輸必須付出的代價。(32-24)/24 = 33.3%。

Q3:前端開發中,什麼情況下應該使用 Base64 Data URI?

當圖片檔案大小在 5KB 以下時,使用 Data URI 嵌入 HTML/CSS 可以減少一次 HTTP 請求,加速首次載入。超過 10KB 的圖片建議使用獨立檔案搭配 CDN,因為過大的 Base64 字串會使 HTML 檔案膨脹,且無法被瀏覽器獨立快取。現代建構工具如 Vite 可自動依據閾值決定是否內嵌。

Q4:Base64URL 和標準 Base64 有什麼差異?該用哪個?

Base64URL 將 + 換成 -/ 換成 _、去除 = 填充,避免這些字元在 URL 中被誤解。當 Base64 編碼後的字串會出現在 URL、JWT Token、檔案名稱中時,必須使用 Base64URL。其他場景使用標準 Base64 即可。

Q5:如何在不安裝軟體的情況下快速進行 Base64 編碼解碼?

你可以使用 Super Tools 的 Base64 編碼解碼工具,在瀏覽器中直接輸入文字或上傳檔案進行轉換。所有運算都在本地完成,資料不會上傳到伺服器。也可以使用瀏覽器開發者工具的 Console,輸入 btoa('text')atob('encoded') 進行快速轉換。

延伸學習資源

如果你正在學習 Web 開發相關的編碼技術,以下 Super Tools 工具可能也對你有幫助:

立即動手試試

理解了 Base64 的原理和應用場景後,最好的學習方式就是實際操作。Super Tools 提供免費的 Base64 編碼解碼工具,支援文字編碼解碼、檔案轉換和 Data URI 生成。不需要安裝任何軟體,直接在瀏覽器中操作,是日常開發中快速轉換的好幫手。立即前往試試,將你的開發效率提升到新的層次!

Base64 在實際專案中的應用技巧

自動化建構工具整合

現代前端建構工具可以自動將小型資源轉為 Base64 Data URI,省去手動操作的麻煩。以下是常見工具的設定方式:

Vite(推薦):

// vite.config.js
export default {
  build: {
    assetsInlineLimit: 4096, // 4KB 以下自動轉 Base64
  }
}

Webpack:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif|svg)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 4 * 1024, // 4KB 閾值
          }
        }
      }
    ]
  }
}

這些設定讓建構工具在打包時自動判斷:檔案小於閾值就轉為 Base64 內嵌,大於閾值就保持獨立檔案。這是目前業界公認的最佳實踐,既能減少小資源的 HTTP 請求數,又不會因為大型 Base64 字串導致 HTML 過度膨脹。

偵錯與資安檢查

Base64 編碼在資安領域也有重要角色。許多惡意程式碼會使用 Base64 混淆來隱藏其真實意圖。如果你在程式碼審查中看到可疑的 Base64 字串,務必解碼檢查其內容:

// 看到這樣的程式碼要提高警覺
eval(atob('YWxlcnQoImhhY2tlZCIp')); // 解碼後是 alert("hacked")

使用 Super Tools 的 Base64 編碼解碼工具 可以快速解碼可疑字串,確認其真實內容。在進行程式碼審查(Code Review)時,對任何直接使用 atob() + eval() 組合的程式碼都應該格外小心。

處理大型檔案的注意事項

當需要對大型檔案進行 Base64 編碼時(例如上傳大型圖片到 API),直接將整個檔案讀入記憶體再編碼可能導致瀏覽器或 Node.js 程序記憶體溢出。建議的做法是:

  1. 前端:使用 FileReader.readAsArrayBuffer() 配合分段處理,或直接使用 FormData 以 multipart/form-data 格式上傳(不經過 Base64)
  2. 後端(Node.js):使用串流(Stream)處理,避免一次讀入整個檔案
  3. 設定合理上限:前端限制上傳檔案大小(例如 5MB),超過則提示使用者壓縮或裁切

對於大型檔案傳輸,Base64 編碼通常不是最佳選擇。直接使用二進位傳輸(如 multipart/form-data)效率更高,因為你不需要承受額外 33% 的大小膨脹。Base64 最適合的場景始終是小型資源的內嵌和文字環境中的二進位資料傳輸。