主頁 > 企業開發 > 由 Base64 展開的知識探討

由 Base64 展開的知識探討

2023-04-14 09:18:14 企業開發

我們是袋鼠云數堆疊 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 是小端序列存盤

一個??,大家可以計算一下,是否真正明白了位元組序

const buffer = new ArrayBuffer(8);
const int8Array = new Int8Array(buffer);
int8Array[0] = 30;
int8Array[1] = 41;

const dataView = new DataView(buffer);
dataView.setInt16(2, 256, true);
const int16Array = new Int16Array(buffer);
console.log(int16Array);  // [10526, 256, 0, 0]
int16Array[0] = 256;
const int8Array1 = new Int8Array(buffer);
console.log(int8Array1);

雖然 TypedArray 無法指定位元組序,但是在存盤的時候采用作業系統默認的位元組序,所以當我們設定 int16Array[0] = 256 時,記憶體中存盤的為 00 01

file

Base64 編碼解碼

什么是 Base64

Base64 是一種基于64個字符來表示二進制資料的方式,

A-Z、a-z、0-9、+、/、= 65個字符組成,值得注意的是 = 用于補位操作

const _base64Str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

Base64 原理

除去 = 這個補位符號,64個字符(即2^6),可表示二進制 000000 至111111共6個位元位,一個位元組有8個位元位,因此可以推算出3個位元組的資料需要用4個 Base64 字符表示

舉個??,this 的 Base64 編碼為 dGhpcw== ,具體編碼如下

file

Base64 編碼解碼實作

在我們的專案中,實作 Base64 編碼通常使用 btoa 和 atob 實作編碼和解碼,下面來嘗試實作 btoa/atob

前置所需要了解函式

  • 獲取相應字符 ASCII 碼方法 String.charCodeAt(index)
  • 取得 Base64 對應的字符方法 String.charAt(index)

編碼實作思路

  • 三個字符分別為 char1/char2/char3,對應的 base64 字符為 encode1/encode2/encode3/encode4
  • encode1 是 char1 取前六位,即 char1 右移2位,encode1 = char1 >> 2
  • encode2 是 char1 后兩位 + char2 前四位組成,encode2 = ((char1 & 3) << 4) | (char2 >> 4)
  • encode3 是 char2 后四位 + char3 前兩位組成,encode3 = ((char2 & 15) << 2) | (char3 >> 6)
  • encode4 是 char3 的后六位,encode4 = char3 & 63
function encodeBase64(input) {
    if (!input) return;
    let base64String = "";
    for (let i = 0; i < input.length; ) {
        const char1 = input.charCodeAt(i++);
        const encode1 = char1 >> 2;
        const char2 = input.charCodeAt(i++);
        const encode2 = ((char1 & 3) << 4) | (char2 >> 4);
        const char3 = input.charCodeAt(i++);
        let encode3 = ((char2 & 15) << 2) | (char3 >> 6);
        let encode4 = char3 & 63;
        if (Number.isNaN(char2)) encode3 = encode4 = 64;
        if (Number.isNaN(char3)) encode4 = 64;
        base64String +=
            _base64Str.charAt(encode1) +
            _base64Str.charAt(encode2) +
            _base64Str.charAt(encode3) +
            _base64Str.charAt(encode4);
    }
    return base64String;
}

解碼實作思路

  • base64 字符為 encode1/encode2/encode3/encode4,三個字符分別為 char1/char2/char3
  • char1 是 encode1 + encode2 前兩位,char1 = (encode1 << 2) | (encode2 >> 4)
  • char2 是 encode2 后四位 + encode3 前四位,char2 = ((encode2 & 15) << 4) | (encode3 >> 2)
  • char3 是 encode3 后兩位 + encode4,char3 = ((encode3 & 3) << 6) | encode4
function decodeBase64(input) {
    if (!input) return;
    let output = "";
    for (let i = 0; i < input.length; ) {
        const encode1 = _base64Str.indexOf(input.charAt(i++));
        const encode2 = _base64Str.indexOf(input.charAt(i++));
        const encode3 = _base64Str.indexOf(input.charAt(i++));
        const encode4 = _base64Str.indexOf(input.charAt(i++));
        const char1 = (encode1 << 2) | (encode2 >> 4);
        const char2 = ((encode2 & 15) << 4) | (encode3 >> 2);
        const char3 = ((encode3 & 3) << 6) | encode4;
        output += String.fromCharCode(char1);
        if (encode3 != 64) {
            output += String.fromCharCode(char2);
        }
        if (encode4 != 64) {
            output += String.fromCharCode(char3);
        }
    }
    return output;
}

一些問題

當我們使用上述代碼去編碼中文的時候,就能夠發現一些問題了,

console.log(encodeBase64("霜序"));                // 8=
console.log(decodeBase64(encodeBase64("霜序")));  // ?

其實是當字符的 Unicode 碼大于255時,上述魔法就會失靈,同樣的 window 上的 btoa 和 atob 方法也會失效,

霜序 兩個字的 Unicode 分別為 38684/24207,那我們可以把這些數字轉化為多個255內的數字,也就是用多個位元組表示,就可以使用我們上述 Unicode 轉 UTF-8 的方法,得到對應的字符,在對齊進行編碼

function encodeTransform(input) {
    if (!input) return;
    const byteArray = [];
    for (let i = 0; i < input.length; i++) {
        const code = input.charCodeAt(i); // 獲取到當前字符的 Unicode 碼
        if (code < 128) {
            byteArray.push(code);
        } else if (code >= 128 && code < 2048) {
            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;  // 回傳 UTF-8 編碼的資料
}

function encodeBase64(input) {
    if (!input) return;
    let base64String = "";
    const byteArray = encodeTransform(input);
    for (let i = 0; i < byteArray.length; ) {
        const char1 = byteArray[i++];
        const encode1 = char1 >> 2;
        const char2 = byteArray[i++];
        const encode2 = ((char1 & 3) << 4) | (char2 >> 4);
        const char3 = byteArray[i++];
        let encode3 = ((char2 & 15) << 2) | (char3 >> 6);
        let encode4 = char3 & 63;
        if (Number.isNaN(char2)) encode3 = encode4 = 64;
        if (Number.isNaN(char3)) encode4 = 64;
        base64String +=
            _base64Str.charAt(encode1) +
            _base64Str.charAt(encode2) +
            _base64Str.charAt(encode3) +
            _base64Str.charAt(encode4);
    }
    return base64String;
}

console.log(encodeBase64("霜序"));     // 6Zyc5bqP

同樣的我們也需要對解碼的內容做相應的轉換,我們需要把 Base64 解碼完成的資料,通過UTF-8的編碼規則還原回 Unicode 碼,找到對應的字符,

function decodeTransform(byteArray) {
    let i = 0;
    const output = [];
    while (i < byteArray.length) {
        const code = byteArray[i];
        if (code < 128) {
            output.push(code);
            i++;
        } else if (code > 191 && code < 224) {
            const code1 = byteArray[i + 1];
            output.push(((code & 31) << 6) | (code1 & 63));
            i += 2;
        } else {
            const code1 = byteArray[i + 1];
            const code2 = byteArray[i + 2];
            output.push(
                ((code & 15) << 12) | ((code1 & 63) << 6) | (code2 & 63)
            );
            i += 3;
        }
    }
    return output.map((item) => String.fromCharCode(item)).join("");
}

function decodeBase64(input) {
    if (!input) return;
    const byteArray = [];
    for (let i = 0; i < input.length; ) {
        const encode1 = _base64Str.indexOf(input.charAt(i++));
        const encode2 = _base64Str.indexOf(input.charAt(i++));
        const encode3 = _base64Str.indexOf(input.charAt(i++));
        const encode4 = _base64Str.indexOf(input.charAt(i++));
        const char1 = (encode1 << 2) | (encode2 >> 4);
        const char2 = ((encode2 & 15) << 4) | (encode3 >> 2);
        const char3 = ((encode3 & 3) << 6) | encode4;
        byteArray.push(char1);
        if (encode3 != 64) {
            byteArray.push(char2);
        }
        if (encode4 != 64) {
            byteArray.push(char3);
        }
    }
    return decodeTransform(byteArray);
}

總結

在本文中,重點是要實作 Base64 編碼的內容,然后先給大家講述了相關字符集(ASCII/Unicode)出現的原因,

Unicode 編碼相關的缺點,由此引出了 UTF-8/UTF-16 編碼,

對于 UTF-16 來說,最小的編碼單元為兩個位元組,由此引出了位元組序的內容,

當我們有了上述知識之后,最后開始 Base64 編碼的實作,

參考鏈接

  • 字符編碼筆記:ASCII,Unicode 和 UTF-8
  • 實作 Base64 的編碼解碼

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/550032.html

標籤:Html/Css

上一篇:漲姿勢了,有意思的氣泡 Loading 效果

下一篇:【D02】Bootstrap免費精選模板推薦,附上Django中使用模板教程

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more