Base64編碼是一種將字節數據編碼爲字符串的編碼,字節數據會被編碼成由64個可打印ASCII字符組成的字符串,這64個字符包括大寫字母A-Z, 小寫字母a-z, 以及數字 0 -9再加上 + 和 / ,恰好64個字符。對應的字符表以下圖:前端
base64編碼的一個用途就是對http的頭信息進行編碼,因爲http頭信息使用ASCII編碼,若是包含特殊字符可能會致使頭信息解析異常,採用base64編碼保證頭信息只包含一些簡單字符,提升了安全性。前端在顯示圖片元素時也常常會遇到base64編碼的圖片資源。數組
那麼base64具體是如何進行編碼的呢?瀏覽器
編碼方式很簡單,就是對目標字節中的每六個bit位表示爲字母表中的某個字符,例如:安全
‘abc’對應的二進制字節爲: 01100001 , 01100010 , 01100011 ; 每六位進行分組獲得的結果以下:async
011000, 010110, 001001, 100011,轉化爲10進制就是:24,22, 9, 35,根據上面的字母表獲得各個數字對應的字符爲:YWJj,因此abc最終會被編碼爲 ‘YWJj’。因爲三個字節最終被編碼成了四個字節的字符串,因此長度增長了1/3.編碼
看着這裏你們可能會有一個問題,假設原數據的字節長度不是3的倍數,就會有剩餘的bit位不夠6個字符,這是就會涉及到填充的問題,填充就是在原數據後面加上額外的冗餘位,使數據的bit位長度恰好能被24(也就是3個字節)整除(6和8的最小公倍數)。具體的填充規則能夠簡單的表述爲: 任何徹底填充(不包含原始數據中的位) 的 6 位組都由特殊的第 65 個符號「=」 表示。 若是 6 位組是部分填充的, 就將填充位設置爲 0(http權威指南)。spa
舉個例子:假設在編碼的過程當中原數組有四個字節,這時就須要再填充2個字節。假設最後的兩個bit爲是10,填充後的數據的最後幾位以下:code
10 xxxx, xxxxxx,xxxxxx (x表明填充位)blog
根據前面描述的填充規則:第一個6位組對應的數字爲 10 0000,後面兩個因爲時徹底填充的,被編碼爲==,最終的結果的後三位就變成了‘g==’。圖片
在瀏覽器端,能夠調用全局的方法 atob 和 btoa 實現二進制字符與base64編碼的字符之間的互相轉化。下面給出一個base64編碼前端實現的簡單例子:
const table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; // 參數爲待編碼的字符串 async function toBase64(str) { const blob = new Blob([str], { type: 'text/plain' }); // 獲取字節長度,也可使用第三方庫提供的同步方法 // 這裏爲了演示簡單 const srcBuf = await blob.arrayBuffer(); // 獲取原數據的字節長度 const length = blob.size; // 計算須要填充的位數 const padLen = length % 3 === 1 ? 2 : length % 3 === 2 ? 1 : 0; // 最終的長度 const size = length + padLen; const arrBuf = new ArrayBuffer(size); const srcArray = new Uint8Array(srcBuf); const dstArray = new Uint8Array(arrBuf); for (let i = 0; i < size; i++) { if (i < length) { dstArray[i] = srcArray[i]; } else { dstArray[i] = 0x00; } } let result = []; // 每次處理3個字節 for (let i = 0; i < size; i += 3) { // 取出三個字節 const a = dstArray[i]; const b = dstArray[i + 1]; const c = dstArray[i + 2]; // 最後一組 const isLast = i + 3 > length; console.log(padLen) result.push(a >> 2); // 第一個字節的前6位 result.push(((a & 0b00000011) << 4) | (b >> 4)); // 第一個字節的後兩位加上第二個字節的前四位 // 第二個字節的後四位加上的三個字節的前兩位 if (!isLast || padLen === 0) { result.push(((b & 0b00001111) << 2) | (c >> 6)); result.push(c & 0b00111111); // 第三個字節的後六位 } else { if (padLen === 2) { result.push('=', '='); } else if (padLen === 1) { result.push(((b & 0b00001111) << 2) | (c >> 6), '='); } } } result = result.map(code => code === '=' ? '=' : table[code]).join(''); return result; }
base64轉二進制字節原理相似,有興趣的童鞋能夠自行嘗試!!
實際的運行效果以下圖: