打开我的简书首页,在地址栏上可以看到这样的地址
作为一个web开发者应该知道这里的users后面的那串"066ab87a062b"必定是我的ID,这个ID肯定是唯一的。这就是今天要讨论的,怎样生成唯一的ID?
如果你是一个初级的web开发者,那么你可能不会去生成这种唯一的ID,因为有一个很简单的方法已经帮我们搞定了这个事情,那就是数据库。
比如我们往数据库的用户表中插入一个用户,数据库的自增键就会生成一个唯一的ID,当然这种ID是很简单的,就是从1开始自增,这样就不会重复。当然这里有很大的安全隐患,从链接上多观察一下,就能发现规律。如果简书现在的链接是这样的:
再多看看其他用户的简书首页地址,你发现也是一个数字,并且修改几个连续的数字大多数能查看到其他用户,那么现在我就可以从ID为1开始遍历,就可以知道简书有多少注册用户了。是不是算暴露了信息?当然黑客可以做的事情远远不止这些。
这个时候我们就得想一个比较复杂的生成唯一ID的想法。
一般来说,我们都会想到用当前系统时间来做这件事情,比如最简单的是unix时间戳,像这样
time();
//1429874998
一般情况下这样是行不通的,因为unix时间戳只是精确到秒,同一秒有两个人注册怎么办?
我记得我一开始实习那会用这个方法来生成唯一ID
time() . rand(1, 10000);
//142987499812
时间戳后面加一个随机数,这样把一秒钟分成10000份,重复的概率只有万分之一,对于一般的情况已经能够搞定了。
但是精明一点的人肯能会猜到你是在用10位的时间戳加一个随机数字,那怎么办?
第一反映自然是加密:
md5(time() . rand(1, 10000));
//141464D2619764441D30A285ED4478F5
不可逆的加密算法有很多,比如md5,sha1等,当然如果使用可逆的加密算法容易被看出来。这样加密一般很难破解了,如果你还觉得不够安全,可以在加密前后进行一系列字符串操作,比如反转。这样就非常难以破解了。当然也有问题,那就是ID变得很长很长。而且似乎也没有解决生成唯一ID的关键问题。
生成唯一ID的关键问题就是唯一,安全问题次之,不是说安全不重要,而是如果连生成唯一ID都解决不了,安全就没有什么可谈的了,系统本身就是不稳定不安全的。
上述的方法还是有一定的概率生成重复ID的,虽然只有万分之一,但如果刚好两个人在同一秒注册,刚好就生成了一样的呢?
php提供了一个生成唯一ID的函数:
uniqid();
//553a2f5bad51f
这个生成的ID就和简书的ID非常像了。
但是这个函数也不一定会生成唯一的ID,原因是uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID;基于微妙的意思就是如果并发数非常非常高的时候,在同一个毫秒里面有两个人注册,那么也是会生成唯一的ID。
正真做到不重复要怎么办?
一种方法是结合时间和数据库生成的ID,这两者结合起来就是唯一的了。
至于怎么结合可以根据自己的需求或者喜好。这样生成的ID只要不进行不可逆加密还可以按时间来排序。
还有一种方法是不借助数据库那个唯一ID,而是将注册流程改为严格的单线程,也就是每次只处理一个,那这样时间戳就是唯一的了,生成方法也就可以随意发挥了。当然了,一两秒的等待用户还是可以接受的。
怎么做到严格的单线程处理注册流程?
第一种简单的就是假设你已经控制好了系统是单线程处理的,我记得以前听过一个鸵鸟算法,像鸵鸟一样将头埋在沙子里面,什么也不做,假装看不到,有时候这何尝不是一种好的生活态度呢。ok,继续说,假设以微妙为单位,这对于90%的系统已经能满足了,因为网站的量根本没有那么大。
第二种方法是用队列来处理,虽然牛刀杀鸡,但也算是个方法。
讲这么多大概讲完了今天想到的东西,最近有点感触就是,遇到的东西多思考你将可能发现更多的好玩的东西。