原生js實現(xiàn)base64編碼方法

@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編碼
  • 可以做解碼過程
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瘫镇,隨后出現(xiàn)的幾起案子鼎兽,更是在濱河造成了極大的恐慌,老刑警劉巖铣除,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谚咬,死亡現(xiàn)場離奇詭異,居然都是意外死亡尚粘,警方通過查閱死者的電腦和手機择卦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來郎嫁,“玉大人秉继,你說我怎么就攤上這事≡箢酰” “怎么了尚辑?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長盔腔。 經(jīng)常有香客問我杠茬,道長月褥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任瓢喉,我火速辦了婚禮宁赤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘栓票。我一直安慰自己决左,他們只是感情好,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布逗载。 她就那樣靜靜地躺著哆窿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪厉斟。 梳的紋絲不亂的頭發(fā)上挚躯,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音擦秽,去河邊找鬼码荔。 笑死,一個胖子當著我的面吹牛感挥,可吹牛的內(nèi)容都是我干的缩搅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼触幼,長吁一口氣:“原來是場噩夢啊……” “哼硼瓣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起置谦,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤堂鲤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后媒峡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘟栖,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年谅阿,在試婚紗的時候發(fā)現(xiàn)自己被綠了半哟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡签餐,死狀恐怖寓涨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情氯檐,我是刑警寧澤缅茉,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站男摧,受9級特大地震影響蔬墩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜耗拓,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一拇颅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乔询,春花似錦樟插、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至食拜,卻和暖如春鸵熟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背负甸。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工流强, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呻待。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓打月,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蚕捉。 傳聞我的和親對象是個殘疾皇子奏篙,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 每個文本編輯器都有默認的編碼方式(比如 UTF-8 編碼),當我們保存文檔的時候迫淹,可以選擇編碼方式秘通,如果沒有特意選...
    _于曼麗_閱讀 1,521評論 0 1
  • 在軟件的編碼和實現(xiàn)中,我們可能會碰到個一個比較頭疼的問題--編碼千绪,不同字符間的編碼和解碼充易,你確定了解各種字符的編碼...
    Java小鋪閱讀 2,518評論 0 5
  • Base64是一種基于64個可打印字符來表示二進制數(shù)據(jù)的表示方法。它已經(jīng)成為網(wǎng)絡(luò)上常見的傳輸8Bit字節(jié)代碼的編碼...
    mysimplebook閱讀 3,140評論 0 3
  • 原文在這里:各種字符集和編碼詳解 在軟件的編碼和實現(xiàn)中盹靴,我們可能會碰到個 一個比較頭疼的問題--編碼瑞妇,不同字符間的...
    舌尖上的大胖閱讀 1,793評論 0 2
  • 守不住寂寞的人默勾,也守不住繁華母剥。 一位老先生曾經(jīng)指點他的弟子: “你只需要靜下心來去鉆研學問,有無教授頭銜又有什么關(guān)...
    悟理趣道閱讀 323評論 2 14