咱們知道一個字節可表示的範圍是 0 ~ 255(十六進制:0x00 ~ 0xFF), 其中 ASCII 值的範圍爲 0 ~ 127(十六進制:0x00 ~ 0x7F);而超過 ASCII 範圍的 128~255(十六進制:0x80 ~ 0xFF)之間的值是不可見字符。javascript
ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)是基於拉丁字母的一套電腦編碼系統。它主要用於顯示現代英語,而其擴展版本延伸美國標準信息交換碼則能夠部分支持其餘西歐語言,並等同於國際標準 ISO/IEC 646。
在 ASCII 碼中 0 - 31和 127 是控制字符,共 33 個。html
其他 95 個,即 32 - 126 是可打印字符,包括數字、大小寫字母、經常使用符號等。java
當不可見字符在網絡上傳輸時,好比說從 A 計算機傳到 B 計算機,每每要通過多個路由設備,因爲不一樣的設備對字符的處理方式有一些不一樣,這樣那些不可見字符就有可能被處理錯誤,這是不利於傳輸的。爲了解決這個問題,咱們能夠先對數據進行編碼,好比 base64 編碼,變成可見字符,也就是 ASCII 碼可表示的可見字符,從而確保數據可靠傳輸。Base64 的內容是有 0 ~ 9,a ~ z,A ~ Z,+,/ 組成,正好 64 個字符,這些字符是在 ASCII 可表示的範圍內,屬於 95 個可見字符的一部分。算法
Base64 是一種基於 64 個可打印字符來表示二進制數據的表示方法。因爲 2⁶ = 64 ,因此每 6 個比特爲一個單元,對應某個可打印字符。3 個字節有 24 個比特,對應於 4 個 base64 單元,即 3 個字節可由 4 個可打印字符來表示。相應的轉換過程以下圖所示:express
Base64 經常使用於在處理文本數據的場合,表示、傳輸、存儲一些二進制數據,包括 MIME 的電子郵件及 XML 的一些複雜數據。在 MIME 格式的電子郵件中,base64 能夠用來將二進制的字節序列數據編碼成 ASCII 字符序列構成的文本。使用時,在傳輸編碼方式中指定 base64。使用的字符包括大小寫拉丁字母各 26 個、數字 10 個、加號 + 和斜槓 /,共 64 個字符,等號 = 用來做爲後綴用途。Base64 相應的索引表以下:segmentfault
瞭解完上述的知識,咱們以編碼 Man
爲例,來直觀的感覺一下編碼過程。Man
由 M、a 和 n 3 個字符組成,它們對應的 ASCII 碼爲 7七、97 和 110。瀏覽器
接着咱們以每 6 個比特爲一個單元,進行 base64 編碼操做,具體以下圖所示:安全
由圖可知,Man
(3字節)編碼的結果爲 TWFu
(4字節),很明顯通過 base64 編碼後體積會增長 1/3。Man
這個字符串的長度恰好是 3,咱們能夠用 4 個 base64 單元來表示。但若是待編碼的字符串長度不是 3 的整數倍時,應該如何處理呢?服務器
若是要編碼的字節數不能被 3 整除,最後會多出 1 個或 2 個字節,那麼可使用下面的方法進行處理:先使用 0 字節值在末尾補足,使其可以被 3 整除,而後再進行 base64 的編碼。網絡
以編碼字符 A 爲例,其所佔的字節數爲 1,不能被 3 整除,須要補 2 個字節,具體以下圖所示:
由上圖可知,字符 A 通過 base64 編碼後的結果是 QQ==
,該結果後面的兩個 =
表明補足的字節數。而最後個 1 個 base64 字節塊有 4 位是 0 值。
接着咱們來看另外一個示例,假設需編碼的字符串爲 BC
,其所佔字節數爲 2,不能被 3 整除,須要補 1 個字節,具體以下圖所示:
由上圖可知,字符串 BC 通過 base64 編碼後的結果是 QkM=
,該結果後面的 1 個 =
表明補足的字節數。而最後個 1 個 base64 字節塊有 2 位是 0 值。
在編寫 HTML 網頁時,對於一些簡單圖片,一般會選擇將圖片內容直接內嵌在網頁中,從而減小沒必要要的網絡請求,可是圖片數據是二進制數據,該怎麼嵌入呢?絕大多數現代瀏覽器都支持一種名爲 Data URLs
的特性,容許使用 base64 對圖片或其餘文件的二進制數據進行編碼,將其做爲文本字符串嵌入網頁中。
<img alt="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...">
但須要注意的是:若是圖片較大,圖片的色彩層次比較豐富,則不適合使用這種方式,由於該圖片通過 base64 編碼後的字符串很是大,會明顯增大 HTML 頁面的大小,從而影響加載速度。除此以外,利用 HTML FileReader API,咱們也能夠方便的實現圖片本地預覽功能,具體代碼以下:
<input type="file" accept="image/*" onchange="loadFile(event)"> <img id="output"/> <script> const loadFile = function(event) { const reader = new FileReader(); reader.onload = function(){ const output = document.querySelector('output'); output.src = reader.result; }; reader.readAsDataURL(event.target.files[0]); }; </script>
在完成本地圖片預覽以後,能夠直接把圖片對應的 Data URLs 數據提交到服務器。針對這種情形,服務端須要作一些相關處理,才能正常保存上傳的圖片,這裏以 Express 爲例,具體處理代碼以下:
const app = require('express')(); app.post('/upload', function(req, res){ let imgData = req.body.imgData; // 獲取POST請求中的base64圖片數據 let base64Data = imgData.replace(/^data:image\/\w+;base64,/, ""); let dataBuffer = Buffer.from(base64Data, 'base64'); fs.writeFile("image.png", dataBuffer, function(err) { if(err){ res.send(err); }else{ res.send("圖片上傳成功!"); } }); });
在 MIME 協議以前,郵件的編碼曾經有過 UUENCODE 等編碼方式 ,可是因爲 MIME 協議算法簡單,而且易於擴展,如今已經成爲郵件編碼方式的主流,不只是用來傳輸 8 位的字符,也能夠用來傳送二進制的文件,如郵件附件中的圖像、音頻等信息,並且擴展了不少基於 MIME 的應用。
在 JavaScript 中,有兩個函數被分別用來處理解碼和編碼 base64 字符串:
const name = 'Semlinker'; const encodedName = btoa(name); console.log(encodedName); // U2VtbGlua2Vy
const encodedName = 'U2VtbGlua2Vy'; const name = atob(encodedName); console.log(name); // Semlinker
對於 atob 和 btoa 這兩個方法來講,其中的 a 表明 ASCII,而 b 表明 Blob,即二進制。所以 atob 表示 ASCII 到二進制,對應的是解碼操做。而 btoa 表示二進制到 ASCII,對應的是編碼操做。在瞭解方法中 a 和 b 分別表明的意義以後,在之後的工做中,咱們就不會用錯了。
Base64 是一種數據編碼方式,目的是爲了保障數據的安全傳輸。但標準的 base64 編碼無需額外的信息,便可以進行解碼,是徹底可逆的。所以在涉及傳輸私密數據時,並不能直接使用 base64 編碼,而是要使用專門的對稱或非對稱加密算法。
本人的全棧修仙之路訂閱號,會按期分享 Angular、TypeScript、Node.js/Java 、Spring 相關文章,歡迎感興趣的小夥伴訂閱哈!