用 Go 無腦解開可有可無 padding 的 Base64 字串
在一個 缺少紀律 人多手雜的開發團隊中,常常會有不同部分是由不同人負責的情形。
今天這個狀況就是一個有趣的例子,不過也可以當作一個有趣的經驗…
認識 Base64 編碼
一直以來都以為我已經知道 Base64 編碼是什麼, 可能這一切要怪 Node.js 環境下 Buffer 做的太無腦防呆, 剛好藉這次機會認識一下 Base64 編碼到底在幹嘛。 如果你覺得你已經認識 Base64 的話可以跳過這裡, 要不然建議你看一下 維基百科
Padding 是什麼
在這裡還是幫大家稍微抓個重點。
Base64 是把 3 個 byte 轉成 4 個 64 進位表示的方式。
(2^6 = 64
,即每 6 個 bit 為一個 64 進位單元。
LCM(8, 6) = 24
,所以就可以得到前面的結論。)
但是當然不可能你要編碼的所有東西長度都會是剛好 3 的倍數,
所以不夠的部分在結尾就用 =
來補上。

不過除了 padding 之外,因為 padding 的作用只是把不足 3 byte 的部分補齊,
所以就算沒有 padding 其實也不會有任何的差異,所以就有沒有 padding 的版本啦~
(就是結尾沒有 =
)
為什麼會混用
這就是個很好的問題了,可能是專案中間經過了很多人,然後交接沒做好, 或者是有人沒看文件就做了, 或者是專案對於這些事情沒有一個統一的規範, 又或者是… 算了,反正就是一些奇怪的原因造成混用了。 然後,Go 對於編碼的要求相對比較嚴謹, 所以就出現了這個奇怪的問題~
Go 裡面的 Base64 編碼
Go 的 Standard Library 其實就已經有對 Base64 處理的 package,
就是 encoding/base64
這個 package。
不過其實他是定義了各種不同的 Base64 encoding,
像是標準的 rfc4648 定義的就是 StdEncoding
,
不過還有另外一個沒有 padding 的 (就是不夠不需要補 =
的版本),
叫做 RawStdEncoding
。
這兩個 encoding 並不相容,所以當結尾沒有 =
但是又需要 padding 的時候,
StdEncoding
就會解不出來,反之亦然。
base64.StdEncoding.DecodeString("QQ==") // ok
base64.StdEncoding.DecodeString("QQ") // illegal base64 data at input byte 0
解決方法
其實解決方式也是蠻明顯的,
就前面的說明我們知道這兩種 encoding 只差在 =
這個結尾的 padding 而已,
所以我們可以把所有的 Base64 都轉成其中一種就可以囉!
例如下面的作法是先把所有的 padding 去掉再進行 decode。
func b64Decode(s string) ([]byte, error) {
return base64.RawStdEncoding.DecodeString(strings.TrimRight(s, "="))
}