js 如何生成唯一且不可预测的 ID
通常数据库可以生成唯一的 ID,最多的就是数字序列,也有像 MongoDB 这样产生组合序列的,不过这种形式的 ID 由于是序列,是可以预测的。如果想得到不可预测且唯一的 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' uuid.v1().replace(/-/g, "") // 产生一个 v4 (随机) id uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1’ uuid.v4().replace(/-/g, "")
听起来很有保证,只是……有点太长了。
坊间也有一些在 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 等等。
上面介绍的两个项目,各有各优缺点,不过目的是一致的,可以根据实际情况选用。两个项目在其它语言上也有类似的实现。