@ "TOC" 常見對base64的認知(不完全正確) 首先對base64常見的認知,也是須知的必須有以下幾點 base64是一種圖片編碼方式,用一長串超長的字元串表示圖片 在載入的時候會直接以字元串的形式載入出來,減少了圖片載入的http請求 正常載入伺服器靜態資源的時候都應該是通過http請求回 ...
目錄
@( 對於前端工程師來說base64圖片編碼到底是個什麼玩意?)
****
----
常見對base64的認知(不完全正確)
首先對base64常見的認知,也是須知的必須有以下幾點*
- base64是一種圖片編碼方式,用一長串超長的字元串表示圖片
- 在載入的時候會直接以字元串的形式載入出來,減少了圖片載入的http請求
- 正常載入伺服器靜態資源的時候都應該是通過http請求回來,每載入一張圖片時需要發起一次http請求 ,http請求建立需要一定的時間,所以對於小圖而且出現頻次比較高的話,這樣的成本消耗其實是特別浪費的
- 所以一般base64編碼適用於小圖片,出現頻次比較高的情況
當然base64編碼也有一定的缺點
- 會增加圖片本上的大小,對於小圖來說,轉碼增加的大小和http請求發起的浪費時間相比還是划算的,但是對於大圖和出現次數比較少的情況,這種方法就有待商榷
- 當然上面我現在項目這種問題就很不合適,肯定需要尋求一個好的方式來解決掉這個問題
多問一個為什麼,base64到底是個啥?
- base64是一種編碼方式,將二進位編碼為64字元串組成的字元碼
- 標準的Base64並不適合直接放在URL里傳輸,因為URL編碼器會把標準Base64中的“/”和“+”字元變為形如“%XX”的形式,而這些“%”號在存入資料庫時還需要再進行轉換,因為ANSI SQL中已將“%”號用作通配符。
- 為解決此問題,可採用一種用於URL的改進Base64編碼,它在末尾填充'='號,並將標準Base64中的“+”和“/”分別改成了“-”和“_”,這樣就免去了在URL編解碼和資料庫存儲時所要作的轉換,避免了編碼信息長度在此過程中的增加,並統一了資料庫、表單等處對象標識符的格式。
- 另有一種用於正則表達式的改進Base64變種,它將“+”和“/”改成了“!”和“-”,因為“+”,“*”以及前面在IRCu中用到的“[”和“]”在正則表達式中都可能具有特殊含義。
- 此外還有一些變種,它們將“+/”改為“-”或“.”(用作編程語言中的標識符名稱)或“.-”(用於XML中的Nmtoken)甚至“_:”(用於XML中的Name)。
- Base64要求把每三個8Bit的位元組轉換為四個6Bit的位元組(38 = 46 = 24),然後把6Bit再添兩位高位0,組成四個8Bit的位元組,也就是說,轉換後的字元串理論上將要比原來的長1/3。
ok,我承認以上都是百度出來了,接下來談談我自己的認識,哈哈
直接掏個例子吧,比如,原生js是自帶base64的編碼方法的
var b = Buffer.from('asdasds'); //buffer 是js裡面專門存放二進位的緩存區,暫時理解創建一個二進位變數
var s = b.toString('base64');
console.log(s)
// YXNkYXNkcw==
按照我們的思路實現一下
- base64是針對二進位對象進行編碼,所以我們要將字元轉換為二進位碼
- base64 是用64個字元表示二進位,2的6次方 = 64,所以base64的字元其實是每6個二進位位為單位,但是一個位元組是8bit,如果不滿6的倍數要往 位元組轉換後的二進位編碼後面補0,比如如果是兩個個字元
'ac' =》 轉換為二進位為:'0110 0001 0110 0010' =》
如果要將這兩個字元進行base64編碼,但是base64僅支持6位二進位轉換為一個字元,
截取之後就是=》 011000 010110 0010
那最後面的4位二進位不夠轉碼,所以會在後面預設補零 - 補碼完成之後開始轉碼 從000000 到111111分別對應
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
64個字元中的一個 轉碼完成
轉換字元為二進位數
function toBinary (str){
let tempResult = [];
let result = [];
// 分割字元
str.split('').forEach(element => {
//轉二進位
let binaryElement = element.charCodeAt().toString(2)
//由於js原生方法轉二進位如果前面是0可能會不滿8位,所以前面補0,轉為8位的對應ascii碼二進位
binaryElement = binaryElement.length === 8 ? binaryElement : ('0' + binaryElement) //不足8位的二進位碼在前面補0
tempResult.push(binaryElement);
});
let index = 0;
// 不滿3個字元往後面補滿3個字元(3個字元(24個二進位位)是6和8的最小公倍數)
while(tempResult.length % 3 != 0){
tempResult.push('00000000')
}
console.log(tempResult.length)
return tempResult.join('');
}
let binary = toBinary('asdasds');
那麼就是第一步和第二步實現了
二進位轉 base64字元串
//將字元串存為數組
let KEYCODE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".split('');
function toBase64 (binary){
console.log(binary);
let tempResult = [];
let result = [];
let index = 0;
// 每6位切割二進位
while(index+6 < binary.length){
tempResult.push(binary.slice(index,index+6))
index = index + 6 ;
}
//不滿6位的前面補0
console.log(binary.slice(index,index+6))
tempResult.push(("000000" + binary.slice(index,index+6)).substr( -6 ));
tempResult.forEach(element => {
//將二進位轉為數組下標
let index = parseInt(element,2);
//獲取對應下標字元串
result.push(index === 0 ? '=' : KEYCODE[index])
});
//字元串拼接
return result.join('')
}
let a = toBase64(binary);
console.log(a);
// YXNkYXNkcw==
到這裡基本就實現了,結果跟原生的方法列印的是一樣的
但是也存在一些問題和改進
對於中文字元和特殊字元的支持
javascript中的中文都是預設utf-16編碼,但是網頁中編碼格式基本都是UTF-8,然而即便我們用UTF-8格式保存了HTML文件,但是其中的中文字元依然是以UTF-16的形式保存的。所以我們首先要將中文字元轉化為utf-8,然後再轉二進位,最後即可用上面的方法進行編碼
代碼如下:var utf16ToUtf8 = function (utf16Str) { var utf8Arr = []; var byteSize = 0; var tempList = []; for (var i = 0; i < utf16Str.length; i++) { //獲取字元Unicode碼值 var code = utf16Str.charCodeAt(i); //如果碼值是1個位元組的範圍,則直接寫入 if (code >= 0x00 && code <= 0x7f) { byteSize += 1; utf8Arr.push(code); //如果碼值是2個位元組以上的範圍,則按規則進行填充補碼轉換 } else if (code >= 0x80 && code <= 0x7ff) { byteSize += 2; utf8Arr.push((192 | (31 & (code >> 6)))); utf8Arr.push((128 | (63 & code))) } else if ((code >= 0x800 && code <= 0xd7ff) || (code >= 0xe000 && code <= 0xffff)) { byteSize += 3; utf8Arr.push((224 | (15 & (code >> 12)))); utf8Arr.push((128 | (63 & (code >> 6)))); utf8Arr.push((128 | (63 & code))) } else if(code >= 0x10000 && code <= 0x10ffff ){ byteSize += 4; utf8Arr.push((240 | (7 & (code >> 18)))); utf8Arr.push((128 | (63 & (code >> 12)))); utf8Arr.push((128 | (63 & (code >> 6)))); utf8Arr.push((128 | (63 & code))) } } var toBin = (n) => { if(n == 0) return '0'; var res = ''; while(n != 0) { res = n % 2 + res n = parseInt(n / 2) } return res; } utf8Arr.forEach(element => { tempList.push(toBin(element)) }); return tempList.join('') }
如何對圖片base64編碼進行實現
圖片的話,要用到canvas ,將圖片轉換為二進位流,然後再掉用上述的編碼方法
下一次
- 可以嘗試圖片的base64編碼
- 可以做解碼過程