需要一個不會與其他人建立的識別碼發生衝突,在一部您從未聽說過的機器上,且無須向任何人請求許可的識別碼嗎?這就是 UUID 的功用。它是一個 128 位元數字,通常以熟悉的 8-4-4-4-12 格式寫成 36 個字元,其整個設計的核心就是即使沒有任何機制協調誰取得哪個,也不會有兩個相同的 UUID。這個免費產生器在您的瀏覽器中產生它們:在「版本」中選擇一個版本,在「數量」中說明您需要多少個,然後按下「產生」。頁面預設開啟的是絕大多數專案所需的單一 v4,因此只需點擊一下即可獲得第一個識別碼。
每個識別碼都由您的瀏覽器透過 Web Crypto API 建構。版本 4 在瀏覽器支援的情況下使用 crypto.randomUUID(),否則使用 crypto.getRandomValues()——這是一個加密等級強度的隨機來源,而不是像 Math.random() 這樣的 JavaScript 偽隨機函式。版本 7 將 48 位元的毫秒時間戳記放在前面,接著是同一毫秒內遞增的 12 位元計數器,然後是 62 個隨機位元,這是 RFC 9562 中描述的排序方法;那個計數器就是為什麼一次產生一千個批次會按順序輸出而不是打亂的原因。版本 1 將時間戳記與設定了多播位元的隨機節點識別碼結合在一起,因此它永遠不會像 1990 年代的原始實作那樣攜帶您的網路卡位址。版本 3 和 5 完全不隨機:它們使用 MD5 和 SHA-1 分別將一個命名空間與一個名稱一起進行雜湊,並且這種雜湊處理同樣是在您的裝置上發生的。沒有任何資料被傳送到伺服器,沒有任何紀錄,而且一旦頁面載入完畢,即使斷開連線它也會繼續運作。
「版本」是決定其他一切的欄位。版本 4 是 122 個隨機位元並且沒有結構——這是預設設定,也是當識別碼只需要具有唯一性時的正確答案。版本 7 保留了 62 個隨機位元,但以它的建立時間開頭,因此一組 v7 可以按其產生順序進行排序;正是這一點使得它成為當識別碼將作為資料庫鍵時的首選版本。版本 1 是原始的基於時間的方案,保留在這裡以供仍要求使用它的系統使用。版本 3 和 5 是特殊的一對:它們是確定性的,這意味著相同的輸入總是產生相同的識別碼,並且它們需要兩個額外的欄位——「命名空間」(標準空間 DNS、URL、OID 和 X.500 之一,或您自己的「自訂」空間)和「名稱」(被識別的字串)。為 v5 提供 URL 命名空間和 https://example.com/a,今天、明天以及在別人的機器上您都會得到相同的 UUID。正因為如此,當選擇 v3 或 v5 時,「數量」會消失:一千份確定性值的副本仍然只是一千份完全相同的副本。對於其他每個版本,「數量」可以從 1 到 1000。
四個開關改變了輸出的形狀,而沒有改變底層的 128 位元。「大寫」將十六進位數字印為大寫字母,「無連字號」提供了某些欄和檔名偏好的 32 字元緊湊形式,而「大括號」將值包裹在 { } 中——這是 Windows 和 .NET 世界稱為 GUID 的形式。在「進階選項」下,urn:uuid: 加上了使其成為正式 URN 的前綴;當它開啟時,會關閉「大括號」和「無連字號」,因為標準只允許一種確切的 URN 形式,那就是帶有連字號的規範形式。「複製格式」決定了取得批次時的連接方式:每行一個、以逗號分隔,或者每個值帶引號並以逗號結尾,以便直接貼上到程式碼的陣列中。結果下方有一行報告位元的隨機性——v4 為 122 位元,v7 為 62 位元——並且對於 v7,還會報告批次中第一個識別碼內編碼的時間戳記,因此值內部的時間是可見的,而不是隱含的。「全部複製」和「儲存為檔案」都遵循「複製格式」的設定。「紀錄」在您的瀏覽器中保留了您最近的 10 個批次:點擊一個即可將其調回,複製或刪除單一項目,或清空全部。「清除」會清空結果但保留您的設定,當識別碼超過 50 個時,清單會變成一個可捲動的區塊而不是五十行。
這個頁面上最重要的一點就是 v4 和 v7 作為主鍵的區別,而且這並不是一個品味問題。資料庫索引是按排序順序保持的 B-tree,新鍵在順序中落入的位置決定了插入操作的代價。v4 鍵是隨機的,因此連續的插入落在索引中互不相關的角落:已滿的頁面被分割,資料庫保留在記憶體中的樹的部分很少是下一次插入所需的部分,最終索引變得比其指向的資料列所對應的規模更大且更破碎化。v7 鍵以當前毫秒開始,因此連續的插入一起落在樹的右邊緣,這是自動遞增整數產生的模式,也是索引結構圍繞其建構的模式。這就是全部的權衡:v7 為您帶來了順序鍵的插入行為,同時保留了讓您最初選擇 UUID 的屬性,即任何人都可以在不請求伺服器的情況下鑄造一個。它的代價是建立時間現在在識別碼內部是可讀的,而這是否要緊是關於您的資料的問題,而不是關於格式的問題。
沒有任何東西會檢查 UUID 的唯一性;其尺寸就是保證。這裡沒有登錄檔,沒有伺服器往返,沒有查閱——產生器產生一個數字並交給您,而其中兩個不發生碰撞的原因僅僅是因為有 2^122 種可能的 v4 值,大約為 5.3 × 10^36。生日問題(birthday problem)是衡量它的最誠實方式:您需要大約 2.7 × 10^18 個識別碼,才能有 50% 的機率使其中任何兩個相符,這相當於在 86 年裡每秒產生十億個新 UUID。精確了解這承諾了什麼和沒承諾什麼是有價值的。這是一種統計上的保證,而非算術上的,並且它僅在底層的隨機性是真實的時候才成立——一個播種不佳的產生器,或一個與其熵池(entropy pool)一起被複製的虛擬機,會以格式無法偵測的方式打破這種保證。版本 7 進一步縮小了這個問題:在單一毫秒內,一個產生器根本不會重複自身,因為計數器是遞增的而不是擲骰子,而在獨立的產生器之間,62 個隨機位元發揮著作用。
UUID 是識別碼,而不是密碼。版本 4 是不可預測的,這誘使人們將其視為秘密——密碼重設連結、不可猜測的 URL、工作階段權杖、API 金鑰。不可預測性是真實的,但保密性是值被處理方式的一種屬性,而識別碼在設計上就是被漫不經心地處理的:它們存在於 URL 中,進入瀏覽器紀錄、伺服器記錄檔、來源標頭和分析中,並被貼上到聊天訊息中。其他版本甚至是更糟糕的選擇。版本 1 和版本 7 都編碼了建立的時間,因此任何持有它的人都能大致知道它是何時產生的,並能縮小與之一起產生的其他事物的範圍。版本 3 和 5 故意是確定性的:一個電子郵件地址的 v5 UUID 不是一個被雜湊的秘密,它是一個任何擁有相同地址的人都可以在一秒鐘內計算出的值。使用 UUID 來命名一個事物。當值必須保持未知時,請使用密碼產生器,或為秘密建構的函式庫中的權杖。
為什麼要選擇這個 UUID 產生器?
- 純瀏覽器端產生:識別碼在您的裝置上產生,絕不會傳送到任何地方
- Web Crypto API 隨機性:密碼學安全,非 Math.random()
- 五種版本集於一處:無需切換工具即可產生 v1、v3、v4、v5 和 v7
- 真正有序的 v7:毫秒內帶有計數器,正如 RFC 9562 所描述
- 確定性的 v3 和 v5,配有四個標準命名空間或您自己的自訂空間
- 一次最多 1000 個,超過五十個時提供緊湊的可捲動清單
- 每種常見形狀:連字號、純文字、大寫字母、帶大括號或 urn:uuid: URN
- 複製格式可選換行、逗號或帶引號的值,直接貼上到程式碼中
- 無限制且免費:免註冊,無使用限制,我們的伺服器上不留存任何東西
UUID 出現的場景,通常是在任何東西能夠確認名字空閒之前,某物必須被命名的時刻。應用程式碼為即將插入的資料列鑄造它們,以便物件在到達資料庫之前就具有識別,並且客戶端可以在寫入操作仍在進行時引用它。分散式系統更加依賴它們:多個服務同時寫入一個資料表,離線的行動客戶端在沒有收訊的地方建立紀錄,一個必須識別其已處理訊息的佇列——所有這些都不能等待共用計數器輪到自己。版本 5 滿足了不同的需求,那是一個從您已經擁有的東西衍生出的穩定識別碼:同一文件、同一 URL 或同一帳號總是映射到相同的 UUID,所以一次匯入可以執行兩次而不複製任何內容。在其他地方,它們僅僅是系統要求的格式——貫穿記錄和追蹤的相關性識別碼,當一千個使用者的上傳進入同一個儲存體時不會發生碰撞的檔名,一個 Windows 登錄機碼,一個必須看起來像真實資料的測試治具。
幾個誠實的限制值得了解。一個批次代表一種版本:「版本」中的值適用於批次中的所有內容,因此一次 v4 產生和一次 v7 產生是兩個不同的批次。這是一個產生器,而不是檢查器——將一個 UUID 貼上進來以回讀它的版本或時間戳記並不是本頁的功能。「儲存為檔案」寫入純文字檔案,而不是 CSV 或 JSON。版本 7 公開揭示它被建立的毫秒級時間,這是一種真正的權衡而不是缺陷,版本 1 以同樣的方式洩漏時間;如果這對您的資料是個問題,版本 4 是那個對誰都不透露任何資訊的版本。標準中有兩個特殊的值不是版本,所以它們不是「版本」中的選項,但您可以從這裡複製它們:nil UUID 即 00000000-0000-0000-0000-000000000000,以及 max UUID 即 ffffffff-ffff-ffff-ffff-ffffffffffff。這個頁面上的一切都遵循 RFC 9562,這是 2024 年取代 RFC 4122 的規範,所以輸出被任何處理 UUID 的函式庫、資料庫或 API 接受。在這些限制內,其保證是強而有力的:每個識別碼都是按照標準、從密碼學安全的隨機性中、在您自己的機器上建構的,而且沒有其他人看過它。