golang - base64简单解读

331 阅读3分钟

前端同学对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…