@TOC
常見對base64的認知(不完全正確)
首先對base64常見的認知世舰,也是須知的必須有以下幾點*
- base64是一種圖片編碼方式唬复,用一長串超長的字符串表示圖片
- 在加載的時候會直接以字符串的形式加載出來,減少了圖片加載的http請求
- 正常加載服務器靜態(tài)資源的時候都應該是通過http請求回來渴杆,每加載一張圖片時需要發(fā)起一次http請求 朽寞,http請求建立需要一定的時間,所以對于小圖而且出現(xiàn)頻次比較高的話,這樣的成本消耗其實是特別浪費的
- 所以一般base64編碼適用于小圖片,出現(xiàn)頻次比較高的情況
當然base64編碼也有一定的缺點
- 會增加圖片本上的大小盖灸,對于小圖來說,轉(zhuǎn)碼增加的大小和http請求發(fā)起的浪費時間相比還是劃算的磺芭,但是對于大圖和出現(xiàn)次數(shù)比較少的情況赁炎,這種方法就有待商榷
- 當然上面我現(xiàn)在項目這種問題就很不合適,肯定需要尋求一個好的方式來解決掉這個問題
多問一個為什么钾腺,base64到底是個啥徙垫?
- base64是一種編碼方式,將二進制編碼為64字符串組成的字符碼
- 標準的Base64并不適合直接放在URL里傳輸放棒,因為URL編碼器會把標準Base64中的“/”和“+”字符變?yōu)樾稳纭?XX”的形式姻报,而這些“%”號在存入數(shù)據(jù)庫時還需要再進行轉(zhuǎn)換,因為ANSI SQL中已將“%”號用作通配符间螟。
- 為解決此問題吴旋,可采用一種用于URL的改進Base64編碼,它在末尾填充'='號厢破,并將標準Base64中的“+”和“/”分別改成了“-”和“_”荣瑟,這樣就免去了在URL編解碼和數(shù)據(jù)庫存儲時所要作的轉(zhuǎn)換,避免了編碼信息長度在此過程中的增加摩泪,并統(tǒng)一了數(shù)據(jù)庫笆焰、表單等處對象標識符的格式。
- 另有一種用于正則表達式的改進Base64變種见坑,它將“+”和“/”改成了“!”和“-”嚷掠,因為“+”,“*”以及前面在IRCu中用到的“[”和“]”在正則表達式中都可能具有特殊含義。
- 此外還有一些變種荞驴,它們將“+/”改為“-”或“.”(用作編程語言中的標識符名稱)或“.-”(用于XML中的Nmtoken)甚至“_:”(用于XML中的Name)不皆。
- Base64要求把每三個8Bit的字節(jié)轉(zhuǎn)換為四個6Bit的字節(jié)(38 = 46 = 24),然后把6Bit再添兩位高位0熊楼,組成四個8Bit的字節(jié)粟焊,也就是說,轉(zhuǎn)換后的字符串理論上將要比原來的長1/3孙蒙。
ok,我承認以上都是百度出來了悲雳,接下來談談我自己的認識挎峦,哈哈
直接掏個例子吧,比如合瓢,原生js是自帶base64的編碼方法的
var b = Buffer.from('asdasds'); //buffer 是js里面專門存放二進制的緩存區(qū)坦胶,暫時理解創(chuàng)建一個二進制變量
var s = b.toString('base64');
console.log(s)
// YXNkYXNkcw==
按照我們的思路實現(xiàn)一下
- base64是針對二進制對象進行編碼,所以我們要將字符轉(zhuǎn)換為二進制碼
- base64 是用64個字符表示二進制,2的6次方 = 64顿苇,所以base64的字符其實是每6個二進制位為單位峭咒,但是一個字節(jié)是8bit,如果不滿6的倍數(shù)要往 字節(jié)轉(zhuǎn)換后的二進制編碼后面補0纪岁,比如如果是兩個個字符
'ac' =》 轉(zhuǎn)換為二進制為:'0110 0001 0110 0010' =》
如果要將這兩個字符進行base64編碼凑队,但是base64僅支持6位二進制轉(zhuǎn)換為一個字符,
截取之后就是=》 011000 010110 0010
那最后面的4位二進制不夠轉(zhuǎn)碼幔翰,所以會在后面默認補零 - 補碼完成之后開始轉(zhuǎn)碼 從000000 到111111分別對應
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
64個字符中的一個 - 轉(zhuǎn)碼完成
轉(zhuǎn)換字符為二進制數(shù)
function toBinary (str){
let tempResult = [];
let result = [];
// 分割字符
str.split('').forEach(element => {
//轉(zhuǎn)二進制
let binaryElement = element.charCodeAt().toString(2)
//由于js原生方法轉(zhuǎn)二進制如果前面是0可能會不滿8位漩氨,所以前面補0,轉(zhuǎn)為8位的對應ascii碼二進制
binaryElement = binaryElement.length === 8 ? binaryElement : ('0' + binaryElement) //不足8位的二進制碼在前面補0
tempResult.push(binaryElement);
});
let index = 0;
// 不滿3個字符往后面補滿3個字符(3個字符(24個二進制位)是6和8的最小公倍數(shù))
while(tempResult.length % 3 != 0){
tempResult.push('00000000')
}
console.log(tempResult.length)
return tempResult.join('');
}
let binary = toBinary('asdasds');
那么就是第一步和第二步實現(xiàn)了
二進制轉(zhuǎn) base64字符串
//將字符串存為數(shù)組
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 => {
//將二進制轉(zhuǎn)為數(shù)組下標
let index = parseInt(element,2);
//獲取對應下標字符串
result.push(index === 0 ? '=' : KEYCODE[index])
});
//字符串拼接
return result.join('')
}
let a = toBase64(binary);
console.log(a);
// YXNkYXNkcw==
到這里基本就實現(xiàn)了遗增,結(jié)果跟原生的方法打印的是一樣的
但是也存在一些問題和改進
-
對于中文字符和特殊字符的支持
javascript中的中文都是默認utf-16編碼叫惊,但是網(wǎng)頁中編碼格式基本都是UTF-8,然而即便我們用UTF-8格式保存了HTML文件,但是其中的中文字符依然是以UTF-16的形式保存的做修。所以我們首先要將中文字符轉(zhuǎn)化為utf-8霍狰,然后再轉(zhuǎn)二進制,最后即可用上面的方法進行編碼
代碼如下: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個字節(jié)的范圍饰及,則直接寫入 if (code >= 0x00 && code <= 0x7f) { byteSize += 1; utf8Arr.push(code); //如果碼值是2個字節(jié)以上的范圍蔗坯,則按規(guī)則進行填充補碼轉(zhuǎn)換 } 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編碼進行實現(xiàn)
圖片的話,要用到canvas 旋炒,將圖片轉(zhuǎn)換為二進制流步悠,然后再掉用上述的編碼方法
下一次
- 可以嘗試圖片的base64編碼
- 可以做解碼過程