你看到一串以==結尾的長字串和數字,心想這是什麼。你將一個JWT貼到工具中,中間的部分大多可讀。你在HTML郵件中嵌入一張圖片,src屬性是一串密密麻麻的字元。你將PDF上傳到API,文件告訴你要「以Base64格式發送」。這些都是同一種編碼,大多數開發者使用它卻從未真正理解其作用。
本指南涵蓋了 Base64 的實際定義、使用時機、常見錯誤(包括最大的錯誤——誤以為它是加密)、URL 安全變體、填充規則,以及在每種主要語言中如何進行編碼和解碼。
Base64 的實際定義
Base64 是一種使用 64 個特定字元將二進位資料轉換為 ASCII 文字的編碼方式:A-Z, a-z,0-9,加上 + 和 /。= 字符用於結尾填充。每 3 個位元組的輸入會產生恰好 4 個 Base64 字元的輸出——這表示 Base64 會使資料大小增加約 33%。
Input bytes: "Hi" (2 bytes: 0x48 0x69)
Binary: 01001000 01101001
Group in 6s: 010010 000110 1001(00) ← last group padded with zeros
Base64 chars: S G k = ← '=' = padding
Result: "SGk="
數學原理:64個字元表示每個字元代表6位元。6位元(一個Base64字元)和8位元(一個位元組)的最小公倍數是24位元——即3個位元組或4個Base64字元。這就是為什麼Base64總是按4個輸出字元為一組運作,以及為什麼需要填充的原因。
最大的誤解:Base64不是加密。
這會同時吸引開發者和非開發者。Base64看起來像亂碼,因此感覺像是一個秘密。但其實它不是。任何人都可以立即解碼Base64——沒有密鑰、沒有密碼、不需要破解演算法。它是一種透明的轉換,就像用不同的字母系統書寫一樣。
// "Encrypted" password?
"cGFzc3dvcmQxMjM="
// Decoded in one line
atob("cGFzc3dvcmQxMjM=")
// → "password123"
Base64是編碼,不是加密。使用它來傳輸 透過純文字通道安全地傳送資料 ─ 切勿使用 hide 資料。若需保密性,請使用真正的加密技術:傳輸中的資料使用 AES、NaCl/libsodium 或 TLS。
何時使用 Base64
Base64 的存在是為了將二進位資料透過預期為文字的系統進行傳遞。最常見的情況:
將二進位資料嵌入 JSON 或 XML — 兩種格式都不支援原始位元組。接受檔案上傳作為 JSON 負載一部分的 API 使用 Base64 來表示檔案。
HTML/CSS 中的資料 URL — data:image/png;base64,iVBORw0KGgo... 讓你可以內嵌圖片而無需單獨的 HTTP 請求。適用於小型圖示和電子郵件簽名。
HTTP 基本認證 — Authorization 標頭將憑證傳送為Basic <base64-of-username:password>. 這也是一個完美的例子,說明為什麼 Base64 不是加密——基本驗證(Basic Auth)只有搭配 HTTPS 時才安全。
JWTs — JSON Web Token 由三個以點分隔的 Base64URL 編碼部分組成。標頭(header)和負載(payload)是可讀的 JSON;只有簽名(signature)是不透明的。
電子郵件附件 — SMTP 在技術上是一種 7 位元文字協定,因此自 MIME 標準以來,附件預設使用 Base64 編碼。
加密金鑰與憑證
— PEM 檔案(-----BEGIN CERTIFICATE----- 區塊)包裝了 Base64 編碼的二進位金鑰。
填補(Padding)— 為什麼有些 Base64 結尾有 =,有些沒有
該=是填充字元。這是因為Base64以3個輸入位元組為一組進行編碼,但並非所有輸入都是3位元組的倍數。當輸入短少了1或2個位元組時,編碼器會用=字元填補輸出,使結果始終為4個字元的倍數。
Input length (mod 3) Padding Example
─────────────────────────────────────────
0 (multiple of 3) none "Man" → "TWFu"
1 == "M" → "TQ=="
2 = "Ma" → "TWE="
某些編碼器和協定會移除填充以節省位元組。JWT 就是如此——JWT 中的 Base64URL 編碼完全沒有填充。如果你手動從 JWT 中解碼 Base64,你可能需要在某些解碼器接受之前重新加上填充。
// JavaScript: add padding back to an unpadded Base64 string
function pad(b64) {
const remainder = b64.length % 4;
return remainder ? b64 + '='.repeat(4 - remainder) : b64;
}
Base64 與 Base64URL——對網路而言重要的變體
標準 Base64 使用+和/作為其第62和第63個字符。兩者在URLs中都具有特殊含義:+在查詢字串中表示「空格」,且/是一個路徑分隔符號。將標準的Base64直接放入URL而不進一步編碼會導致問題。
Base64URL(定義於 RFC 4648)透過交換這些字元來解決此問題:+成為-,而/變成_。它通常也會省略填充。結果可以直接安全地放入URL、檔案名稱和HTTP標頭中。
Standard Base64: "abc/d+ef=="
Base64URL: "abc_d-ef"
// Convert one to the other
const toUrlSafe = (b64) => b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const fromUrlSafe = (b64u) => {
const b64 = b64u.replace(/-/g, '+').replace(/_/g, '/');
return pad(b64); // add padding back
};
JWT使用Base64URL。大多數現代令牌格式、OAuth狀態參數以及任何在URL中傳輸的內容也是如此。
在JavaScript中進行編碼和解碼
JavaScript 有兩個內建函式:btoa()(二進位轉 ASCII,編碼)和 atob()(ASCII 轉二進位,解碼)。這兩個名稱很容易混淆——因為它們對任意二進位資料的處理方式並不符合直覺。
// Simple ASCII strings — these work
btoa("Hello, world!");
// → "SGVsbG8sIHdvcmxkIQ=="
atob("SGVsbG8sIHdvcmxkIQ==");
// → "Hello, world!"
// Unicode strings — this BREAKS
btoa("héllo");
// → DOMException: invalid character
// Correct way for Unicode: encode to UTF-8 first
function utf8ToBase64(str) {
return btoa(unescape(encodeURIComponent(str)));
}
function base64ToUtf8(b64) {
return decodeURIComponent(escape(atob(b64)));
}
utf8ToBase64("héllo"); // → "aMOpbGxv"
base64ToUtf8("aMOpbGxv"); // → "héllo"
// Modern alternative (Node 16+, modern browsers)
const bytes = new TextEncoder().encode("héllo");
const b64 = btoa(String.fromCharCode(...bytes));
對於檔案上傳這類二進位資料,請使用 ArrayBuffer(Uint8Array)或 Uint8Array(ArrayBuffer):
// Convert a file to Base64 (browser)
async function fileToBase64(file) {
const buffer = await file.arrayBuffer();
const bytes = new Uint8Array(buffer);
let binary = '';
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary);
}
// FileReader alternative — gives you a data URL
function fileToDataUrl(file) {
return new Promise(resolve => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.readAsDataURL(file);
});
}
Python 中的編碼與解碼
import base64
# Encode a string
encoded = base64.b64encode(b"Hello, world!")
# → b"SGVsbG8sIHdvcmxkIQ=="
# Decode
decoded = base64.b64decode(b"SGVsbG8sIHdvcmxkIQ==")
# → b"Hello, world!"
# URL-safe variant — for JWTs, URLs, filenames
url_safe = base64.urlsafe_b64encode(b"data with /and+chars")
# → b"ZGF0YSB3aXRoIC9hbmQrY2hhcnM="
# Encode a file
with open("photo.jpg", "rb") as f:
encoded_file = base64.b64encode(f.read()).decode("ascii")
命令列中的編碼與解碼
# macOS and Linux — encode
echo -n "Hello, world!" | base64
# → SGVsbG8sIHdvcmxkIQ==
# Decode
echo "SGVsbG8sIHdvcmxkIQ==" | base64 -d
# → Hello, world!
# Encode a file
base64 photo.jpg > photo.txt
# Decode a file
base64 -d photo.txt > photo.jpg
# Watch out — many systems wrap output at 76 characters by default
# Use -w 0 (GNU) or no flag (BSD) to disable wrapping
echo -n "long content..." | base64 -w 0
SQL 中的編碼與解碼
-- PostgreSQL
SELECT encode('Hello, world!'::bytea, 'base64');
-- → SGVsbG8sIHdvcmxkIQ==
SELECT convert_from(decode('SGVsbG8sIHdvcmxkIQ==', 'base64'), 'UTF8');
-- → Hello, world!
-- MySQL 8+
SELECT TO_BASE64('Hello, world!');
-- → SGVsbG8sIHdvcmxkIQ==
SELECT FROM_BASE64('SGVsbG8sIHdvcmxkIQ==');
-- → Hello, world!
常見錯誤及其避免方法
換行陷阱。某些實作(特別是 MIME 和 OpenSSL)會在 Base64 輸出中每 64 或 76 個字元換行。其他實作則拒絕包含換行符的輸入。如果您在解碼看似有效的 Base64 時看到「無效字元」錯誤,請先去除空白字元。
填充不匹配。 JWT 與 URL 安全的 Base64 通常會省略填充。許多解碼器需要填充。如果解碼失敗,請計算需要新增多少個 = 字元:(4 - (length % 4)) % 4 個。
UTF-8 假設。 Base64 編碼的是位元組,而非字元。對字串進行編碼時,必須先確定它所使用的字元編碼。務必明確指定編碼方式(UTF-8 幾乎永遠是正確選擇),並在將結果視為字串前,先解碼回位元組。
關於大小的意外。 Base64 會使酬載大小增加 33%。對於小型資源來說,這無關緊要。但對於嵌入在 JSON 中的 10 MB 檔案,影響就大了——你將在網路上傳輸 13.3 MB。對於較大的檔案,建議使用多部分上傳。
將其視為機密。值得說兩次:Base64不是加密。不要將密碼、API金鑰或其他敏感資料存儲為Base64,期望它被隱藏。如果你能看到編碼後的字串,你就能看到原始內容。
我是William,DevCrate的開發者。Base64工具 的存在是因為我厭倦了將偽隨機字串丟進可疑的線上轉換器來查看內容。它能編碼和解碼標準及 URL-safe 兩種變體,處理檔案,且不會將任何一個位元組送出你的機器。
如果本指南沒有涵蓋某個 Base64 情況,請在留言中提出——我會仔細閱讀每一則。












