golang - base64簡單解讀

國傑發表於2019-01-02

前端同學對base64的認識,往往是 圖片可以用base64的方式來顯示.

其實我們前後端最常用的jwt驗證也是base64這種編碼的.

今天就單獨說base64編碼本身.

宣告

base64編碼我們要看的是他的過程和標準.下面舉例程式碼非js,但基本思路都是一樣的,因為標準就一個.

上程式碼


const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

// The encoding pads the output to a multiple of 4 bytes,
// so Encode is not appropriate for use on individual blocks
// of a large data stream. Use NewEncoder() instead.
func (enc *Encoding) Encode(dst, src []byte) {
	if len(src) == 0 {
		return
	}

	di, si := 0, 0
	// 能被3整除的最大的數
	// 標準中說明3個位元組要被轉換為 4個 6bits的組
	// a 24-bit input group is formed by concatenating 3 8-bit input groups.
	n := (len(src) / 3) * 3
	// n個組,每組是3個位元組
	for si < n {
		// Convert 3x 8bit source bytes into 4 bytes
		// 第一個8bits後面+16個0
		// 第二個8bits後面+8個0
		// 第三個8bits
		// val ->  [第一個8bits][第二個8bits][第三個8bits] 連線在一起 24bits
		val := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2])
		// 取出最左6bits給 dst[0]
		// 7-12 中間6bits給dst[1]
		// 依次放入dst 共4組,每組6bits
		dst[di+0] = enc.encode[val>>18&0x3F]
		dst[di+1] = enc.encode[val>>12&0x3F]
		dst[di+2] = enc.encode[val>>6&0x3F]
		dst[di+3] = enc.encode[val&0x3F]

		si += 3
		di += 4
	}
	// 不能被整除剩餘的位元組
	// 有的字可能2個或者1個位元組就能表示了
	// (1) The final quantum of encoding input is an integral multiple of 24
	//    bits; here, the final unit of encoded output will be an integral
	//    multiple of 4 characters with no "=" padding.
	remain := len(src) - si
	if remain == 0 {
		return
	}
	// Add the remaining small block
	// 拿到字元對應的ascii碼,並左移16位 相當於 * 2^16
	// val是多出的第一個位元組
	val := uint(src[si+0]) << 16
	// 如果多出2個位元組的情況 val 就是 [多出的第一個8bits][多出的第二個8bits][8個0] 共24bits連線
	if remain == 2 {
		val |= uint(src[si+1]) << 8
	}
	// 取最左6bits
	// 6位都是1也就是63,在64內,拿到對應的字元進入dst
	dst[di+0] = enc.encode[val>>18&0x3F]
	// 取中間6bits
	dst[di+1] = enc.encode[val>>12&0x3F]

	switch remain {
	case 2:
		// 	(3) The final quantum of encoding input is exactly 16 bits; here, the
		//    final unit of encoded output will be three characters followed by
		//    one "=" padding character.
		// 取第三個6bits出來
		dst[di+2] = enc.encode[val>>6&0x3F]
		if enc.padChar != NoPadding {
			// 根據標準要+一個pad
			dst[di+3] = byte(enc.padChar)
		}
	case 1:
		// 	(2) The final quantum of encoding input is exactly 8 bits; here, the
		//    final unit of encoded output will be two characters followed by
		//    two "=" padding characters.
		if enc.padChar != NoPadding {
			// 根據標準+2個pad
			dst[di+2] = byte(enc.padChar)
			dst[di+3] = byte(enc.padChar)
		}
	}
}

複製程式碼

上面程式碼只是針對標準的encode做出了說明.

對於URLencode 會有些不同

主要區別是

const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" 請對比上面的標準字符集 const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

想看具體標準內容的,請走傳送門 tools.ietf.org/html/rfc464…

相關文章