由 JavaScript 產生的 UUID,是一個 128 位元的識別碼,以標準的 8-4-4-4-12 格式,寫成 32 個十六進位數字——例如 f47ac10b-58cc-4372-a567-0e02b2c3d479——其中第 13 個十六進位數字固定為 4(代表版本),第 17 個則固定為 8、9、a 或 b(代表變體),因此 128 個位元中有 6 個被保留下來,剩下 122 個位元可以自由用於隨機性。正是這 122 個位元的隨機資料量,讓 v4 版本的 UUID,在任何實際應用程式會產生的量級下,實質上不會發生碰撞。在 JavaScript 中,填滿這 122 個位元最安全的做法,是使用 Web Crypto API 的 crypto.getRandomValues,它會從瀏覽器具備密碼學安全性的亂數產生器中取值。「UUID」這個簡稱代表 Universally Unique IDentifier(通用唯一識別碼),而 v4 這個變體,是 RFC 4122 及其在 2024 年的後繼規範 RFC 9562 中所定義、完全隨機的版本——這種識別碼可以在任何裝置上、在任何地方獨立產生,不需要向中央登錄機構回報。正是這種不需要協調的特性,讓許多 JavaScript 技術堆疊,會預設用 v4 來產生資料庫鍵值、冪等性權杖、日誌關聯 ID 與檔案名稱。

how to generate uuid in javascript
如何在 javascript 中產生 uuid

UUID v4 實際上長什麼樣子

每一個 v4 版本的 UUID,都是一個 128 位元的值,以 32 個十六進位字元表示,分成 8、4、4、4、12 個數字一組的五個區塊,中間用連字號分隔。因此標準的文字形式長度是 36 個字元——32 個十六進位數字加上 4 個連字號。在這 128 個位元中,恰好有 6 個不是隨機的:4 個位元用來編碼版本,2 個位元用來編碼變體。因為 v4 會把版本值 4 存在第 13 個十六進位數字的高半位元組中,所以這個數字永遠是字元 4。變體位元則位於第 17 個十六進位數字的最高兩個位元中,因此這個數字永遠是 8、9、a 或 b 其中之一。任何人只要檢查這兩個位置,就能辨識出一個 v4 版本的 UUID——這就是整份規格的指紋所在。

能夠辨識版本與變體,也讓您可以一眼看出 v4 與其他 UUID 版本的差別。第 13 個十六進位數字,會依照版本不同而編碼成 1、3、4、5 或 7;第 17 個數字的規則則適用於所有版本,因為變體欄位是共用的。這種以連字號分組的外形、固定的版本半位元組,以及固定的變體半位元組,三者共同定義了在程式碼審查、日誌管線,或資料庫欄位限制中,「看起來像 v4」到底代表什麼。

為什麼隨機來源在 JavaScript 中很重要

v4 版本 UUID 中那 122 個隨機位元,必須來自某個地方,而這個來源非常重要。一段簡短的 JavaScript 程式碼,可以呼叫 Math.random() 並格式化輸出,產生一個看起來像 UUID 的字串,但 Math.random 並不具備密碼學安全性:它的確定性強到,看過幾筆輸出結果的攻擊者,有時候可以預測後續的值,而且這個演算法在不同引擎之間也不一致。瀏覽器安全的做法是 crypto.getRandomValues,它取用的,是與 TLS 交握及其他安全關鍵 API 相同的密碼學安全亂數產生器(CSPRNG)。

這正是為什麼UUID 產生器所產生的識別碼,可以安全地暴露在網址、日誌與用戶端程式碼中的核心原因:每一個值,都是在您的分頁中用 crypto.getRandomValues 產生出來的。用 CSPRNG 取出的這 122 個位元,讓每一次輸出,在統計上都與前一次輸出獨立——沒有共用的種子、沒有時鐘、沒有 MAC 位址,也沒有混入任何命名空間。正是這項特性,讓兩個互不相關的服務,可以在同一時刻各自產生識別碼,卻仍然有信心不會發生碰撞。跳過 CSPRNG 所付出的代價,並不只是理論上的:一個可被預測的識別碼,可能被猜中、被重放,或是在不同請求之間被關聯起來,而這正是安全審查在拒絕以弱隨機性建構的識別碼時,所指出的那種失效模式。

在您的瀏覽器中產生 UUID

不寫任何一行程式碼,就能產生單一 UUID 或一整批 UUID 最快的方法,就是這個瀏覽器內的 UUID 產生器。整個流程都在本機執行,因此識別碼在任何網路往返之前就已經準備好。

  1. 開啟 UUID 產生器,輸入您想要的 UUID 數量,範圍從 1 到 100。
  2. 如果您的資料庫欄位或程式碼風格需要不同的文字形式,可以切換 大寫 讓十六進位數字變成大寫,或者切換 移除連字號 拿掉這四個分隔符號,產生一個連續的 32 字元字串。
  3. 點擊 產生。清單就會重新整理,顯示從您瀏覽器的 CSPRNG 取出的全新 v4 版本 UUID。
  4. 把滑鼠移到任何一列上,複製那一個單獨的 UUID,或使用 全部複製 一次把整批結果都複製到剪貼簿。

因為這個工具是在您的分頁中執行,您可以無限次重複這個步驟:每點擊一次「產生」,就會產生全新的一批,而且您可以在每次執行之間變更格式切換選項,不會遺失先前產生的值。對於也想在實際程式碼中測試這些值的開發者,JavaScript 練習場 是一個實用的搭配工具——把產生出來的 UUID 貼進一段程式碼片段中,在上線之前,用您真正的驗證邏輯測試它。

選擇輸出格式

有三個切換選項,決定了 UUID 產生器回傳的文字形式。它們都不會改變底層的 128 位元數值,因此這只是純粹依照您下游系統的需求所做的選擇。

切換選項文字形式範例是否為相同的值?
預設小寫,含連字號f47ac10b-58cc-4372-a567-0e02b2c3d479
大寫大寫十六進位,含連字號F47AC10B-58CC-4372-A567-0E02B2C3D479
不含連字號小寫,不含分隔符號f47ac10b58cc4372a5670e02b2c3d479
兩者皆是大寫十六進位,不含分隔符號F47AC10B58CC4372A5670E02B2C3D479

資料庫欄位經常儲存標準的 36 字元形式,因為它符合規格,但有些權杖系統、標頭值與內嵌識別碼,偏好使用 32 字元、不含連字號的形式,以節省空間或配合固定寬度的欄位。如果您的技術堆疊,用不區分大小寫的方式比較 UUID,大寫選項就沒有影響;如果是用區分大小寫的方式比較,請堅持使用小寫,以免最後得到兩個外觀不同、卻代表同一個識別碼的字串。

什麼時候該選擇 UUID v4

對於任何需要由兩個系統各自獨立產生、不需要協調的識別碼而言,版本 4 都是正確的預設選擇——這正是 JavaScript 開發者經常遇到的情境。

UUID 版本位元來源典型的 JavaScript 使用情境
v1時間戳記 + MAC 位址在 JS 中很少使用;可能洩漏主機資訊
v3命名空間 + 名稱的 MD5 雜湊值由已知輸入產生確定性的識別碼
v4來自 CSPRNG 的 122 個隨機位元資料庫鍵值、冪等性權杖、追蹤 ID、檔案名稱
v5命名空間 + 名稱的 SHA-1 雜湊值與 v3 相同,但使用更強的雜湊演算法
v7毫秒時間戳記 + 隨機尾端為索引局部性提供時間排序的鍵值

實際的使用案例,都與 v4 相符:需要在同步之前先建立紀錄的分散式與離線優先系統、防止 API 呼叫重複的冪等性鍵值、貫穿整個日誌管線的關聯 ID,以及跨服務時不得發生碰撞的物件或檔案名稱。對這些情境而言,不含任何時鐘、MAC 位址或命名空間輸入,正是一項優點——因為根本沒有可以洩漏的東西,也沒有需要協調的東西。

值得特別一提的唯一例外,是 UUIDv7。如果您把 UUID 儲存在依主鍵建立索引的資料庫中,並且在意索引的局部性——也就是新寫入的資料,總是落在索引尾端附近,而不是隨機散落各處——那麼 v7 這種以時間排序的前置部分,會是更好的選擇。而對於較常見的、不要求順序的唯一性需求,v4 仍然是預設選擇。

僅在瀏覽器中產生與安全性

這個產生器所產生的每一個 UUID,都是在您的瀏覽器分頁中,用 crypto.getRandomValues 於本機計算出來的。您產生或複製的任何內容,都不會傳送到伺服器,因此這個工具無論用於正式環境的識別碼,還是內部機密資料,都可以安全使用。這項保證,是來自實作方式本身,而不是來自一項隱私承諾:這個頁面從不會對任何 UUID 後端開啟網路連線,而剪貼簿輸出,是這個值唯一會前往的地方。

為了讓碰撞的數學更具體,我們就以 122 個隨機位元為例。生日界限——也就是一組集合中,至少出現一次重複的機率達到 50% 的那個點——大約是 2.71 × 10^18。把這個數字除以每秒 10^9 個 UUID,再除以每年 31,536,000 秒,會得到大約 86 年——也就是說,以每秒十億個 UUID 的速度持續產生,大約要經過這麼久,才會讓出現一次重複的機率超過一半。這正是分散式系統,在不跨機器協調的情況下,把 v4 版本的 UUID 視為實質上唯一的根本原因,也正是讓它們能在瀏覽器分頁中安全產生的那項特性。

對 JavaScript 開發者而言,實際上的結論很簡短。對於任何需要無法被猜測的用途,請跳過 Math.random()。在程式碼中使用 crypto.getRandomValues(),而當您需要一個值、卻來不及自己寫程式碼片段時,就使用 UUID 產生器——輸出結果,是同樣的 122 位元隨機識別碼,只是產生的過程中沒有經過網路往返。如果您需要核對規格細節,標準的參考文件是 RFC 4122,並由 RFC 9562 更新,其中確切定義了版本與變體位元該如何設定。