DEV Community

Cover image for Web 傳輸的摩斯密碼,base64介紹
Kevin Luo
Kevin Luo

Posted on • Updated on

Web 傳輸的摩斯密碼,base64介紹

因為看到 ruby3 的 release note 裡特別有講把 base64 放上 rubygems.org
https://github.com/ruby/base64
也讓我想到好像至今沒有真的了解base64在做什麼...。
就是每次處理非純文字的資料時,
都是把檔案轉成 base64 的字串表示。
比如在 rails 上傳圖片時,圖片在 params 中就是 base64 的形式,
而且另個疑問是,為什麼要稱那些資料為 Binary data 呢?

預設你已了解 bit 跟 byte 還有字的編碼如 ASCII,讀起來較易理解

參考資料

當然是 Wiki Base64 - Wikipedia

base64

base64 可以想成「用 64 種字元」去代表所有的資料的一種方式

因為電腦其實只認 0 跟 1
所以資料不論是何種類型,到最後一定會變成是 0 跟 1 的組合。例如:

  • 數字 6 會轉成二進位的 110
  • 字元 A 是 100 0001(因為 ASCII 裡 A=65,而65的二進位是 100 0001)
  • 字串是字元連起來的,所以是一長串的 01 組合

base64 是把 01 這種二進位的資料,以 6 個為一組呈現的方式
任 6 位數 2 進位,如 000 001, 001 101
總共會有64種組合,所以命名為 base64

給每種組合一個代表的「字元 Char」,
就可以用那64種字元去代表所有的字串了,
(如果bits數不能被 6 整除,會用 = 去代替)
下表是 wiki 上列出這64個字元:
alt text

以 Wiki頁 上的例子 Man 這個字串來說,
ASCII 是用 8 bits 存的,所以 共有 24 bits
轉成 base64:

  • M 是 010011 01, 前面6 bit 010011依上表 是 T ,然後剩 2 bit 01
  • a 是 0110 0001,前面的4 bit 配上 M 後 2 bit, 010110 是 W
  • 依續做可得 TWFu alt text

我們可以用這個方式拆解中文試看看:

'我'.unpack("B*")[0]  # 將 String 轉二進位
# "111001101000100010010001"
Enter fullscreen mode Exit fullscreen mode

剛好是 3 個 byte 也就是 24bits 所以用 base64 恰好是 4 個字元顯示
alt text

require 'base64'
puts Base64.encode64('我')
# 5oiR

# 注意decode base64時,它不知道那是 utf-8 所以要自己轉回去
Base64.decode64('5oiR')
# "\xE6\x88\x91" 
Base64.decode64('5oiR').encoding
# #<Encoding:ASCII-8BIT> 
Base64.decode64('5oiR').force_encoding('UTF-8')
# "我"
Enter fullscreen mode Exit fullscreen mode

而那些根本不是任何「文字」的檔案,比如說圖片、音樂、影片,
根本不能轉成文字,但依然可以以 0 跟 1 表示,
可以寫成超長的011010101010....的字串,
就稱它們為 Binary data

在傳送檔案時,就可以用 base64 去表示任何檔案,
又因為 base64 轉回來時只是一般的 ASCII,所以才為什麼一定要加註
Content-Type 或副檔名。

Q&A

base64 最終還不是會換為 0 與 1,為什麼不直接傳 01 就好了?

可參考這篇答案,老實說我也是驚覺xD
algorithm - Why do we use Base64? - Stack Overflow
主要原因還是希望傳輸的內容人易看懂,即使 base64 是不可讀的,但英數真的比較容易分辨2串字一不一樣

感謝網友指正,因為某些通訊協定或資料格式直接規定訊息內不能放 binary data,比如最常拿來舉例的就是 email 格式的 MIME,直接規定只允許 ASCII 的字元。那圖片跟其它附加檔案都是 binary data 怎麼辦?用 base64 即可將 binary data 轉成 ASCII 並附在 email 的訊息中。

此外,
避免不同系統對不同的編碼解讀不同。
如用 base64 傳輸資料,即使兩邊系統解讀不同,
至少可以同意「資料本身」是兩邊一致的,
以 Stackoverflow 上的例子來說,傳兩行的訊息時:

Hello
world!
Enter fullscreen mode Exit fullscreen mode

ASCII 的編碼是長

72 101 108 108 111 10 119 111 114 108 100 33
Enter fullscreen mode Exit fullscreen mode

那個換行符號 10, 在不同的作業系統解讀是不一樣的
如果用 base64

SGVsbG8Kd29ybGQh
Enter fullscreen mode Exit fullscreen mode

一樣都是 ASCII,但都是較「安全」的,也就是所有系統都一致的

83 71 86 115 98 71 56 75 100 50 57 121 98 71 81 104
Enter fullscreen mode Exit fullscreen mode

不過這則留言還是滿好笑的xD

問題留言有一位 Martin 回
We use base64 because it's more readable than Perl
笑死xD

為何不干脆來個 base128, base256? 不是能變更短

這問題也非常有意思,我也這樣想過
encoding - Why is base128 not used? - Stack Overflow
因為base64的字元其實都是 ASCII 中英文數字這類較「安全」的字元,
就是為了所有電腦都能顯示。
從上面的程式碼例子也知道 decode 完預設是 ASCII 的編碼。
base128 的話 勢必會用到 ASCII 裡的控制碼了,
換行 \n 或讓電腦叫一聲那種,這在每個作業系統的意義可能不同,
這樣就失去互通性了

希望有幫助到大家理解喔

Top comments (0)