如何生成唯一且不可預測的 ID
下面主要以 Node.js 的環境爲例。
Node-uuid
Github 上有個 node-uuid 項目,它可以快速地生成符合 RFC4122 規範 version 1 或者 version 4 的 UUID。
安裝,既可以通過 npm install node-uuid ,也可以在 package.json 中定義。使用方式:
var uuid = require('node-uuid'); // 產生一個 v1 (基於時間的) id uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a' // 產生一個 v4 (隨機) id uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1’
聽起來很有保證,只是……有點太長了。
坊間也有一些在 UUID 基礎上隨機截取幾位的辦法來組成一個新的短一點的字符串,只不過唯一性就又重新成爲一個問號了。
Hashids
另外一個方法,來自 hashids,它的原理就是從數字經過一個加鹽(salted)算法產生一個哈希(hash)字符串。這樣算法就是通過混淆使結果具有不可預測性,而唯一性依然由數字本身來達成,從而得到(類似 youtube 裏的)足夠短,不可預測且唯一的 ID。
安裝方式類似,只是 hashids 建議使用一個固定的版本。比如在 package.json 中
"dependencies": { "hashids": "0.3.3" }
使用方法也很簡單。先設定一個字符串作爲 salt。
var Hashids = require("hashids"), hashids = new Hashids("this is my salt”);
然後對數字(準確來說是數字數組)進行編碼
var hash = hashids.encrypt(12345); // Nkk9 var hash = hashids.encrypt(683, 94108, 123, 5); // aBMswoO2UB3Sj
對數組編碼可以有很有趣的用法,比如需要在一個分佈式的環境裏使用,可以使用機器編號 + 序列數字組合數組然後再編碼。
有編碼就有解碼
var numbers = hashids.decrypt("NkK9”); // [12345]
編碼的輸出會隨着數字的增大而變長,爲了達到足夠混淆,它可以指定最少長度。
hashids = new Hashids("this is my salt", 8); var hash = hashids.encrypt(1); // gB0NV05e
還有其它選項,比如控制輸出所使用的字符,編碼 MongoDB 的 ObjectId 等等。
上面介紹的兩個項目,各有各優缺點,不過目的是一致的,可以根據實際情況選用。兩個項目在其它語言上也有類似的實現。