前端對base64編碼的理解,原生js實現字元base64編碼

来源:https://www.cnblogs.com/zclub/archive/2019/08/26/11412255.html
-Advertisement-
Play Games

@ "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編碼
  • 可以做解碼過程

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Flex佈局 對於我們平常遇到的問題的解決方法。 1.在父容器中的垂直居中。 2.使容器內的子項占據等量的空間(寬、高)。 3.使容器內的列等高排列。 線上查看Flex佈局示例及其屬性使用,效果展現: "線上示例" 下麵是各個屬性的描述: 設置容器的display屬性為flex,如果是行內元素使用 ...
  • 示例代碼托管在: "http://www.github.com/dashnowords/blogs" 博客園地址: "《大史住在大前端》原創博文目錄" 華為雲社區地址: "【你要的前端打怪升級指南】" [TOC] 一. 需求分析 為另一個項目提供可嵌入的功能單頁,大部分頁面使用時都是獨立功能頁,個別 ...
  • 1. isNaN() 存在的意義 由於 NaN 是唯一一個不等於自身的值,不像其他的值,可以用相等操作符來判斷是否等於自身, 和`NaN === NaN false isNaN()`就誕生了,那它到底起著怎樣的作用呢,且看下文。 2. isNaN() 判斷的原理 函數接受一個參數,原理是先嘗試將參數 ...
  • <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title></title> <sc ...
  • 先簡單說下每個方法對應的語句和用法 obj.appendChild(node) 把新的子節點添加到指定節點(插入新的子節點(元素)),這麼說可能不是很明白,代碼可能更清晰哈!node表示的就是要添加的節點。 但是這個方法只能在父節點的末尾添加元素。那如果我們要在父元素的中間添加怎麼辦呢。w3c又提供 ...
  • 單例模式 保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。 單例模式是一種常用的模式,有一些對象我們往往只需要一個,比如線程池、全局緩存、瀏覽器中的 window 對象等。 JavaScript 中的單例模式 1. 使用命名空間 在JavaScript里,實現單例的方式有很多種,其中最簡單的一 ...
  • 1、只顯示一行,超出部分用省略號 2、只顯示兩行(或多行),超出部分用省略號 ...
  • JavaScript中的時間是通過定時器控制的,他們分別是window.setInterval和window.setTimeout,我們當然可以省略window,直接使用方法名稱調用。 一 setTimeout 在等待指定的毫秒數後執行函數,語法如下: setTimeout(code/functio ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...