<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
平靜之下,驀然回首,base64 卻在燈火闌珊處。
今天翻開舊專案發現挺多圖片相關的外掛都是用 base64 來顯示圖片的。談到 base64,腦海遐想翩翩,思緒迴盪之下 base64 瑕瑜互見。本文旨在記錄工作中遇見的問題並加以總結,如有不妥請指正~
base64 是網路傳輸 8Bit 位元組程式碼的編碼方式之一,是一種基於 64 個可列印字元來表示二進位制資料的方法。在做支付系統時,報文互動都需要使用 base64 對明文進行轉碼,然後再進行簽名或加密,之後再進行(或再次 base64 轉碼)傳輸。那麼,base64 到底起到什麼作用呢?
在引數傳輸的過程中經常遇到的一種情況:使用全英文的字串沒問題,但一旦涉及到中文就會出現亂碼的情況。與此類似,網路上傳輸的字元並不全是可列印的字元,比如二進位制檔案、圖片等。base64 的出現就是為了解決此問題,它是基於 64 個可列印的字元來表示二進位制的資料的一種方法。
電子郵件剛問世的時候,只能傳輸英文,但後來隨著使用者的增加,中文、日韓俄文等文字的使用者也有需求,但這些字元並不能被伺服器或閘道器有效處理,因此 base64 就登場了。隨後,base64 在 URL、Cookie、網頁傳輸少量二進位制檔案中也有相應的使用。
基於a-z
、A-Z
、0-9
、+/
這 64 個字元來標識二進位制資料,另外=
符號用於當位元組缺位時補用。
base64 編碼對照表
索引 | 對應字元 | 索引 | 對應字元 | 索引 | 對應字元 | 索引 | 對應字元 |
0 | A | 17 | R | 34 | i | 51 | z |
1 | B | 18 | S | 35 | j | 52 | 0 |
2 | C | 19 | T | 36 | k | 53 | 1 |
3 | D | 20 | U | 37 | l | 54 | 2 |
4 | E | 21 | V | 38 | m | 55 | 3 |
5 | F | 22 | W | 39 | n | 56 | 4 |
6 | G | 23 | X | 40 | o | 57 | 5 |
7 | H | 24 | Y | 41 | p | 58 | 6 |
8 | I | 25 | Z | 42 | q | 59 | 7 |
9 | J | 26 | a | 43 | r | 60 | 8 |
10 | K | 27 | b | 44 | s | 61 | 9 |
11 | L | 28 | c | 45 | t | 62 | + |
12 | M | 29 | d | 46 | u | 63 | / |
13 | N | 30 | e | 47 | v | ||
14 | O | 31 | f | 48 | w | ||
15 | P | 32 | g | 49 | x | ||
16 | Q | 33 | h | 50 | y |
base64 要求把每三個 8Bit
的位元組轉換
為四個 6Bit
的位元組(3*8 = 4*6 = 24
),然後把 6Bit再添兩位高位 0
,組成四個 8Bit 的位元組(4*8=32
)。
為什麼使用 3 個位元組一組呢?因為 6 和 8 的最小公倍數
為 24,三個位元組正好 24 個二進位制位,每 6 個 bit 位一組,恰好能夠分為 4 組。
同時用於分組後每組新增兩個高位 0,轉換後
的字串理論上
將要比原來的字元長 1/3(24/32=1/3)
。
步驟分解:
將待轉換的字串每三個字元分為一組,每個字元位元組佔 8bit,那麼共有 24 個二進位制位。
將 24 個二進位制位每 6 個位元組為一組,共分為 4 組。
在每組 6 位元組前面新增兩個 0,每組由 6 位元組變為 8 位元組二進位制位,組成總共 32 個二進位制位,即四個位元組。
根據 base64 編碼對照表獲得對應的值。
舉個栗子
LJY
為例。LJY
對應的 ASCII 碼值分別為 76、74、89,對應的二進位制值是 01001100、01001010、01011001。由此組成一個 24 位的二進位制位字串。
將 24 位的二進位制位字串,按照每 6 位二進位制位一組分成 4 組。
對 4 組 每組 6 位二進位制位字串前面補兩個 0,每組擴充套件為 8 位二進位制位,4 組共擴充套件成 32 個二進位制位,此時 4 組二進位制位分別為:00010011、00000100、00101001、00011001。其對應的 base64 編碼索引為:19、4、41、25。
用 base64 編碼索引值在 base64 編碼表中進行查詢,分別對應:T、E、p、Z。
LJY
base64 編碼之後就變為:TEpZ。| 文字 | L | J | Y | | ASCII | 76 | 74 | 89 | | 二進位制位 | 01001100 | 01001010 | 01011001 | | 分組二進位制 | 010011 | 000100 | 101001 | 011001 | | 分組二進位制補2個0 | 00010011 | 00000100 | 00101001 | 00011001 | | 分組索引 | 19 | 4 | 41 | 25 | | base64編碼 | T | E | p | Z | 主要展示: 轉換前二進位制位: 01001100 01001010 01011001 轉換後二進位制位: 00010011 00000100 00101001 00011001 複製程式碼
上述栗子是面向剛好三個字元為一組的情況。當然不是所有時候都這麼巧字元位數足夠,除此以外有位數不足的情況。那麼,面對字元位數不足的情況下該如何處理呢?
base64 給出的方案是,當每組字元不足三位時,不足位數位置需要使用=
符號補上。
位數不足情況處理情景:
=
補上。=
補上。位數不足圖解如下:
<!-- 缺2位字元,字串以A為例轉換base64後位QQ== --> | 文字(1Byte) | A | | | | 二進位制位 | 01000001 | | | | 分組二進位制 | 010000 | 010000 | | | | 分組二進位制補0 | 00010000 | 00010000 | | | | 分組索引 | 16 | 16 | | | | base64編碼 | Q | Q | = | = | <!-- 缺1位字元,字串以AB為例轉換base64後位QUI= --> | 文字(1Byte) | A | B | | | 二進位制位 | 01000001 | 01000010 | | | 分組二進位制 | 010000 | 010100 | 001000 | | | 分組二進位制補0 | 00010000 | 00010100 | 00001000 | | | 分組索引 | 16 | 20 | 8 | | | base64編碼 | Q | U | I | = | 複製程式碼
列舉了一個字元到三個字元轉換為 base64 ,可以發現將 base64 就是按照 base64 編碼對照表來將二進位制轉換為字串,使得資料不能直接明文展示出來,但也算不上是加密,而這巧好可用在傳輸、儲存、表示二進位制領域的情景。
知道 base64 是什麼後,也該到為什麼出現了。為什麼要是使用 base64 呢,這要從其優缺點入手來選擇適合場景了。
enCodedData,是一個通過 btoa() 方法編碼的字串, 為二進位制字串包含 base64 編碼的資料。並返回包含來自 encodedData 的解碼資料的 ASCII 字串。
stringToEncode 為要編碼的二進位制字串。並返回包含 stringToEncode 的 base64 表示形式的 ASCII 字串。
另外在 JavaScript 中,字串使用 UTF-16 字元編碼表示:在這種編碼中,字串表示為 16 位(2 位元組)單元的序列。每個 ASCII 字元都可以放入其中一個單元的第一個位元組,但許多其他字元不能。
base64 在設計上需要二進位制資料作為其輸入。就 JavaScript 字串而言,這意味著每個字元只佔用一個位元組的字串。因此,如果將一個字串傳遞到 btoa()中,其中包含佔用多個位元組的字元,則會出現錯誤,因為這不被視為二進位制資料,因此超 16 位字元在使用 btoa()時需要先對字元轉碼為二進位制位。
// 簡單資料 const encodedData = btoa('Hello, world'); // encode a string const decodedData = atob(encodedData); // decode the string /* 複雜資料 */ // convert a Unicode string to a string in which // each 16-bit unit occupies only one byte function toBinary(string) { const codeUnits = new Uint16Array(string.length); for (let i = 0; i < codeUnits.length; i++) { codeUnits[i] = string.charCodeAt(i); } const charCodes = new Uint8Array(codeUnits.buffer); let result = ''; for (let i = 0; i < charCodes.byteLength; i++) { result += String.fromCharCode(charCodes[i]); } return result; } function fromBinary(binary) { const bytes = new Uint8Array(binary.length); for (let i = 0; i < bytes.length; i++) { bytes[i] = binary.charCodeAt(i); } const charCodes = new Uint16Array(bytes.buffer); let result = ''; for (let i = 0; i < charCodes.length; i++) { result += String.fromCharCode(charCodes[i]); } return result; } // a string that contains characters occupying > 1 byte const myString = '☸☹☺☻☼☾☿'; const converted = toBinary(myString); const encoded = btoa(converted); console.log(encoded); // OCY5JjomOyY8Jj4mPyY= const decoded = atob(encoded); const original = fromBinary(decoded); console.log(original); // ☸☹☺☻☼☾☿
// base64編碼表 const map = { 0: 52, 1: 53, 2: 54, 3: 55, 4: 56, 5: 57, 6: 58, 7: 59, 8: 60, 9: 61, A: 0, B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9, K: 10, L: 11, M: 12, N: 13, O: 14, P: 15, Q: 16, R: 17, S: 18, T: 19, U: 20, V: 21, W: 22, X: 23, Y: 24, Z: 25, a: 26, b: 27, c: 28, d: 29, e: 30, f: 31, g: 32, h: 33, i: 34, j: 35, k: 36, l: 37, m: 38, n: 39, o: 40, p: 41, q: 42, r: 43, s: 44, t: 45, u: 46, v: 47, w: 48, x: 49, y: 50, z: 51, '+': 62, '/': 63, }; function base64to2(base64) { let len = base64.length * 0.75; // 轉換為int8array所需長度 base64 = base64.replace(/=*$/, ''); // 去掉=號(佔位的) const int8 = new Int8Array(len); //設定int8array檢視 let arr1, arr2, arr3, arr4, p = 0; for (let i = 0; i < base64.length; i += 4) { arr1 = map[base64[i]]; // 每次迴圈 都將base644個位元組轉換為3個int8array直接 arr2 = map[base64[i + 1]]; arr3 = map[base64[i + 2]]; arr4 = map[base64[i + 3]]; // 假設資料arr 資料 00101011 00101111 00110011 00110001 int8[p++] = (arr1 << 2) | (arr2 >> 4); // 上面的操作 arr1向左邊移動2位 變為10101100 // arr2 向右移動4位元:00000010 // | 為'與'操作: 10101110 int8[p++] = (arr2 << 4) | (arr3 >> 2); int8[p++] = (arr3 << 6) | arr4; } return int8; }
// base64圖片轉blob function base64toBlob(base64) { var arr = base64.split(','), mime = arr[0].match(/:(.*?);/)[1] || 'image/png', bstr = atob(arr[1]), // 將base64轉為Unicode規則編碼 n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); // 轉換編碼後才可以使用charCodeAt 找到Unicode編碼 } return new Blob([u8arr], { type: mime }); } /* 優化版 */ function base64ToBlob(base64) { var arr = base64.split(','); var mime = arr[0].match(/:(.*?);/)[1] || 'image/png'; // 去掉url的頭,並轉化為byte var bytes = window.atob(arr[1]); // 處理異常,將ascii碼小於0的轉換為大於0 var ab = new ArrayBuffer(bytes.length); // 生成檢視(直接針對記憶體):8位元無符號整數,長度1個位元組 var u8arr = new Uint8Array(ab); for (var i = 0; i < bytes.length; i++) { u8arr[i] = bytes.charCodeAt(i); } return new Blob([u8arr], { type: mime }); }
到此這篇關於一文講清base64編碼原理的文章就介紹到這了,更多相關base64編碼內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45