由 Base64 展開的知識探討

来源:https://www.cnblogs.com/dtux/archive/2023/04/13/17314672.html
-Advertisement-
Play Games

我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。。 本文作者:霜序(掘金) 前言 在我們的業務應用中越來越多的應用到編碼內容,例如在 API 中,給到後端的 SQL 都是通過 Base64 加密的數據等等。 能夠發現我 ...


我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。。

本文作者:霜序(掘金)

前言

在我們的業務應用中越來越多的應用到編碼內容,例如在 API 中,給到後端的 SQL 都是通過 Base64 加密的數據等等。

能夠發現我們的代碼中,使用的 window 對象上的 btoa 方法實現的 Base64 編碼,那 btoa 具體是如何實現的呢?將在下麵的內容中為大家講解。

那我們就先從一些基礎知識開始深入瞭解吧~

什麼是編碼

編碼,是信息從一種形式轉變為另一種形式的過程,簡要來說就是語言的翻譯。

將機器語言(二進位)轉變為自然語言。

五花八門的編碼

ASCII 碼

ASCII 碼是一種字元編碼標準,用於將數字、字母和其他字元轉換為電腦可以理解的二進位數。

它最初是由美國信息交換標準所制定的,它包含了 128 個字元,其中包括了數字、大小寫字母、標點符號、控制字元等等。

在電腦中一個位元組可以表示256眾不同的狀態,就對應256字元,從 00000000 到 11111111。ASCII 碼一共規定了128字元,所以只需要占用一個位元組的後面7位,最前面一位均為0,所以 ASCII 碼對應的二進位位 00000000 到 01111111。

file

非 ASCII 碼

當其他國家需要使用電腦顯示的時候就無法使用 ASCII 碼如此少量的映射方法。因此技術革新開始啦。

  • GB2312
    收錄了6700+的漢字,使用兩個位元組作為編碼字元集的空間
  • GBK
    GBK 在保證不和 GB2312/ASCII 衝突的情況下,使用兩個位元組的方式編碼了更多的漢字,達到了2w
  • 等等

全面統一的 Unicode

面對五花八門的編碼方式,同一個二進位數會被解釋為不同的符號,如果使用錯誤的編碼的方式去讀區文件,就會出現亂碼的問題。

那能否創建一種編碼能夠將所有的符號納入其中,每一個符號都有唯一對應的編碼,那麼亂碼問題就會消失。因此 Unicode 藉此機會統一江湖。是由一個叫做 Unicode 聯盟的官方組織在維護。

Unicode 最常用的就是使用兩個位元組來表示一個字元(如果是更為偏僻的字元,可能所需位元組更多)。現代操作系統都直接支持 Unicode。

Unicode 和 ASCII 的區別

  • ASCII 編碼通常是一個位元組,Unicode 編碼通常是兩個位元組.
    字母 A 用 ASCII 編碼十進位為 65,二進位位 01000001;而在 Unicode 編碼中,需要在前面全部補0,即為 00000000 01000001
  • 問題產生了,雖然使用 Unicode 解決亂碼的問題,但是為純英文的情況,存儲空間會大一倍,傳輸和存儲都不划算。

問題對應的解決方案之UTF-8

UTF-8 全名為 8-bit Unicode Transformation Format

本著節約的精神,又出現了把 Unicode 編碼轉為可變長編碼的 UTF-8。可以根據不同字元而變化位元組長度,使用1~4位元組表示一個符號。UTF-8 是 Unicode 的實現方式之一。

UTF-8 的編碼規則

  1. 對於單位元組的符號,位元組的第一位設置為0,後面七位為該字元的 Unicode 碼。因此對於英文字母,UTF-8 編碼和 ASCII 編碼是相同的。
  2. 對於 n 位元組的符號,第一個位元組的前 n 位都是1,第 n+1 位為0,後面的位元組的前兩位均為10。剩下的位所填充的二進位就是這個字元的 Unicode 碼

對應的編碼表格

Unicode 符號範圍 UTF-8 編碼方式
0000 0000-0000 007F (0-127) 0xxxxxxx
0000 0080-0000 07FF (128-2047) 110xxxxx 10xxxxxx
0000 0800-0000 FFFF (2048-65535) 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF (65536往上) 11110xxx 10xxxxxx 10xxxxxx 10xxxxxxx

在 Unicode 對應表中查找到“杪”所在的位置,以及其對應的十六進位 676A,對應的十進位為 26474(110011101101010),對應三個位元組 1110xxxx 10xxxxxx 10xxxxxx

將110011101101010的最後一個二進位依次填充到1110xxxx 10xxxxxx 10xxxxxx從後往前的 x ,多出的位補0即可,中,得到11100110 10011101 10101010 ,轉換得到39a76a,即是杪字對應的 UTF-8 的編碼

file

  • >> 向右移動,前面補 0, 如 104 >> 2 即 01101000=> 00011010
  • & 與運算,只有兩個操作數相應的比特位都是 1 時,結果才為 1,否則為 0。如 104 & 3即 01101000 & 00000011 => 00000000,& 運算也用在取位時
  • | 或運算,對於每一個比特位,當兩個操作數相應的比特位至少有一個 1 時,結果為 1,否則為 0。如 01101000 | 00000011 => 01101011
function unicodeToByte(input) {
    if (!input) return;
    const byteArray = [];
    for (let i = 0; i < input.length; i++) {
        const code = input.charCodeAt(i); // 獲取到當前字元的 Unicode 碼
        if (code < 127) {
            byteArray.push(code);
        } else if (code >= 128 && code < 2047) {
            byteArray.push((code >> 6) | 192);
            byteArray.push((code & 63) | 128);
        } else if (code >= 2048 && code < 65535) {
            byteArray.push((code >> 12) | 224);
            byteArray.push(((code >> 6) & 63) | 128);
            byteArray.push((code & 63) | 128);
        }
    }
    return byteArray.map((item) => parseInt(item.toString(2)));
}

問題對應的解決方案之UTF-16

UTF-16 全名為 16-bit Unicode Transformation Format
在 Unicode 編碼中,最常用的字元是0-65535,UTF-16 將0–65535範圍內的字元編碼成2個位元組,超過這個的用4個位元組編碼

UTF-16 編碼規則

  1. 對於 Unicode 碼小於 0x10000 的字元, 使用2個位元組存儲,並且是直接存儲 Unicode 碼,不用進行編碼轉換
  2. 對於 Unicode 碼在 0x10000 和 0x10FFFF 之間的字元,使用 4 個位元組存儲,這 4 個位元組分成前後兩部分,每個部分各兩個位元組,其中,前面兩個位元組的前 6 位二進位固定為 110110,後面兩個位元組的前 6 位二進位固定為 110111,前後部分各剩餘 10 位二進位表示符號的 Unicode 碼 減去 0x10000 的結果
  3. 大於 0x10FFFF 的 Unicode 碼無法用 UTF-16 編碼

對應的編碼表格

Unicode 符號範圍 具體Unicode碼 UTF-16 編碼方式 位元組
0000 0000-0000 FFFF (0-65535) xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 2位元組
0001 0000-0010 FFFF (65536往上) yy yyyyyyyy xx xxxxxxxx 110110yy yyyyyyyy 110111xx xxxxxxxx 4位元組

“杪”字的 Unicode 碼為 676A(26474),小於 65535,所以對應的 UTF-16 編碼也為 676A
找一個大於 0x10000 的字元,0x1101F,進行 UTF-16 編碼
file

位元組序

對於上述講到的 UTF-16 來說,它存在一個位元組序的概念。

位元組序就是位元組之間的順序,當傳輸或者存儲時,如果超過一個位元組,需要指定位元組間的順序。

最小編碼單元是多位元組才會有位元組序的問題存在,UTF-8 最小編碼單元是一個位元組,所以它是沒有位元組序的問題,UTF-16 最小編碼單元是兩個位元組,在解析一個 UTF-16 字元之前,需要知道每個編碼單元的位元組序。

為什麼會出現位元組序?
電腦電路先處理低位位元組,效率比較高,因為計算都是從低位開始的。所以,電腦的內部處理都是小端位元組序。但是,人類還是習慣讀寫大端位元組序。
所以,除了電腦的內部處理,其他的場合比如網路傳輸和文件儲存,幾乎都是用的大端位元組序。
正是因為這些原因才有了位元組序。

比如:前面提到過,"杪"字的 Unicode 碼是 676A,"橧"字的 Unicode 碼是 6A67,當我們收到一個 UTF-16 位元組流 676A 時,電腦如何識別它表示的是字元 "杪"還是 字元 "橧"呢 ?

對於多位元組的編碼單元需要有一個標識顯式的告訴電腦,按著什麼樣的順序解析字元,也就是位元組序。

  • 大端位元組序(Big-Endian),表示高位位元組在前面,低位位元組在後面。高位位元組保存在記憶體的低地址端,低位位元組保存在在記憶體的高地址端。
  • 小端位元組序(Little-Endian),表示低位位元組在前,高位位元組在後面。高位位元組保存在記憶體的高地址端,而低位位元組保存在記憶體的低地址端。
    file

簡單聊聊 ArrayBuffer 和 TypedArray、DataView

ArrayBuffer

ArrayBuffer 是一段存儲二進位的記憶體,是位元組數組。

它不能夠被直接讀寫,需要創建視圖來對它進行操作,指定具體格式操作二進位數據。

可以通過它創建連續的記憶體區域,參數是記憶體大小(byte),預設初始值都是 0

TypedArray

ArrayBuffer 的一種操作視圖,數據都存儲到底層的 ArrayBuffer 中

const buf = new ArrayBuffer(8);
const int8Array = new Int8Array(buf);
int8Array[3] = 44;
const int16Array = new Int16Array(buf);
int16Array[0] = 42;
console.log(int16Array); // [42, 11264, 0, 0]
console.log(int8Array);  // [42, 0, 0, 44, 0, 0, 0, 0]

使用 int8 和 int16 兩種方式新建的視圖是相互影響的,都是直接修改的底層 buffer 的數據

DataView

DataView 是另一種操作視圖,並且支持設置位元組序

const buf = new ArrayBuffer(24);
const dataview = new DataView(buf);
dataView.setInt16(1, 3000, true);  // 小端序

明確電腦的位元組序

上述講到,在存儲多位元組的時候,我們會採用不同的位元組序來做存儲。那對我們的操作系統來說是有一種預設的位元組序的。下麵就用上述知識來明確 MacOS 的預設位元組序。

function isLittleEndian() {
    const buf = new ArrayBuffer(2);
    const view = new Int8Array(buf);
    view[0]=1;
    view[1]=0;
    console.log(view);
    const int16Array = new Int16Array(buf);
    return int16Array[0] === 1;
}
console.log(isLittleEndian());

通過上述代碼我們可以得出此款 MacOS 是小端序列存儲

一個

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

-Advertisement-
Play Games
更多相關文章
  • 4月22日下午14:00,雲資料庫技術和NineData主辦的「MySQL x ClickHouse」技術沙龍,將在杭州市海智中心3號樓1102報告廳舉辦。本次沙龍以“技術進化,讓數據更智能”為主題,匯聚位元組跳動、阿裡雲、玖章算術、華為雲、騰訊雲等眾多資料庫廠商的技術大咖, 圍繞MySQL x Cl... ...
  • 新媒體時代,廣告樣式越來越豐富。相較於傳統的圖文信息,視頻類廣告更具有直觀性,能夠讓消費者在瞭解產品知識和功能的同時加深對產品的印象。 因此在各類網站或App上投放視頻類廣告是個很好的宣傳方式,但廣告商們如果想在網站上展示視頻廣告,必須確保視頻廣告投放協議與發佈渠道的播放器相容;如果不能相容,廣告商 ...
  • ChatBox 是什麼 開源的 ChatGPT API (OpenAI API) 桌面客戶端,Prompt 的調試與管理工具,支持 Windows、Mac 和 Linux。 為什麼需要它 每次想訪問 ChatGPT 時,都需要在瀏覽器中輸入 ChatGPT 網址,然後點擊登錄,選擇賬號,整個過程中比 ...
  • 今天解決了我自認為一個很不起眼的Bug。 我的Tabs下麵有5個tabPane,並且這幾個tabPane共用了一個search組件,今天遇到了一個bug,就是這幾個組件使用公共查找組件的時候,前一個組件的值會影響下一個組件的值。 找了半天發現,原來我應該在父組件Tabs中定義一個useState的狀 ...
  • 項目忙完,這次上新,寫一個前端系列,採用vue3來開發一個微信公眾號商城。 前言: 1. 微信公眾號商城本質也是一個網站,由一個個網頁組成,只不過這些網頁運行在手機端,能響應手指的點擊、長按、拖拽等操作。 2. 既然是網頁,當然可以用3件套(js+html+css)來寫,但象vue這樣的前端框架比3 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 平時在使用v-for的時候,一般會要求傳入key,有沒有像我一樣的小伙伴,為了省心,直接傳索引index,貌似也沒有遇到過什麼問題,直到有一天,我遇到一個這樣的需求 場景 在一個下單界面,我需要去商品列表選商品,然後在下單界面遍歷顯 ...
  • 前端模板 - Anchor UI KIT 前言 今天介紹一款製作精良、開源、免費的 Bootstrap 模板 —— Anchor UI KIT 該模板使用的是Bootstrap v4版本 本文將介紹如何在Django中導入該模板的靜態資源包並使用 介紹 官方文檔 Anchor - a free Bo ...
  • Promise 是非同步編程的一種解決方案,比傳統的回調函數或事件更合理和更靈活。 Promise 方法 Promise的原型方法:then/catch/finally,這三種方法很常用,then用於處理Promise轉為fulfilled狀態時的代碼,catch用於處理Promise轉為reject ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...