在JavaScript中创建GUID / UUID?

时间:2020-03-06 14:27:37  来源:igfitidea点击:

我正在尝试在JavaScript中创建全局唯一标识符。我不确定所有浏览器上都提供哪些例程,内置随机数生成器的"随机性"和种子状态如何,等等。

GUID / UUID至少应包含32个字符,并且应保持在ASCII范围内,以免在传递它们时遇到麻烦。

解决方案

已经对此进行了几次尝试。问题是:我们要使用实际的GUID,还是只需要看起来像GUID的随机数?生成随机数很容易。

function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

但是,请注意,这些值不是真正的GUID。

注意:提供的代码段不遵循RFC4122,这要求版本(4)必须集成到生成的输出字符串中。如果我们需要兼容的GUID,请不要使用此答案。

使用:

var uuid = guid();
function guid() {
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
    s4() + '-' + s4() + s4() + s4();
}

function s4() {
  return Math.floor((1 + Math.random()) * 0x10000)
    .toString(16)
    .substring(1);
}

document.getElementById('jsGenId').addEventListener('click', function() {
  document.getElementById('jsIdResult').value = guid();
})
input { font-family: monospace; }
<button id="jsGenId" type="button">Generate GUID</button>
<br>
<input id="jsIdResult" type="text" placeholder="Results will be placed here..." readonly size="40"/>

来自sagi shkedy的技术博客:

function generateGuid() {
  var result, i, j;
  result = '';
  for(j=0; j<32; j++) {
    if( j == 8 || j == 12|| j == 16|| j == 20) 
      result = result + '-';
    i = Math.floor(Math.random()*16).toString(16).toUpperCase();
    result = result + i;
  }
  return result;
}

还有其他涉及使用ActiveX控件的方法,但请远离这些方法!

编辑:我认为值得指出的是,没有GUID生成器可以保证唯一键(请参阅Wikipedia文章)。总是有碰撞的机会。 GUID仅提供足够大的键范围,以将冲突的变化减少到几乎为零。

Web服务将很有用。

快速的Google找到了:http://www.hoskinson.net/GuidGenerator/

无法保证该实现,但SOMEONE必须发布真实的GUID生成器。

使用这种Web服务,我们可以开发一个REST Web界面,该界面使用GUID Web服务,并通过AJAX将其提供给浏览器中的javascript。

从好的OL维基百科开始,有指向UUID的javascript实现的链接。

它看起来相当优雅,也许可以通过对客户端IP地址的哈希值加盐来进行改进。此哈希可能可以插入到html文档服务器端,以供客户端javascript使用。

更新:原始站点已改组,这是更新的版本

这是一些基于RFC 4122,第4.4节(根据真正随机数或者伪随机数创建UUID的算法)的代码。

function createUUID() {
    // http://www.ietf.org/rfc/rfc4122.txt
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = "-";

    var uuid = s.join("");
    return uuid;
}

此创建版本4 UUID(从伪随机数创建):

function uuid()
{
   var chars = '0123456789abcdef'.split('');

   var uuid = [], rnd = Math.random, r;
   uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
   uuid[14] = '4'; // version 4

   for (var i = 0; i < 36; i++)
   {
      if (!uuid[i])
      {
         r = 0 | rnd()*16;

         uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf];
      }
   }

   return uuid.join('');
}

这是生成的UUID的示例:

682db637-0f31-4847-9cdf-25ba9613a75c
97d19478-3ab2-4aa1-b8cc-a1c3540f54aa
2eed04c9-2692-456d-a0fd-51012f947136

对于符合RFC4122版本4的解决方案,此一站式解决方案是我能想到的最紧凑的解决方案。

function uuidv4() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

console.log(uuidv4())

更新,2015-06-02:请注意,UUID的唯一性很大程度上取决于基础随机数生成器(RNG)。为了简洁起见,以上解决方案使用Math.random(),但是不能保证Math.random()是高质量的RNG。有关详细信息,请参见Adam Hyland在Math.random()上的出色文章。对于更强大的解决方案,请考虑使用uuid模块[免责声明:我是作者]之类的东西,该模块会在可用时使用更高质量的RNG API。

更新,2015-08-26:作为旁注,本要点描述了如何确定在达到一定的碰撞概率之前可以生成多少个ID。例如,使用3.26x1015版本4 RFC4122 UUID,我们有百万分之一的碰撞机会。

更新,2017-06-28:Chrome开发人员的一篇好文章,讨论了Chrome,Firefox和Safari中Math.random PRNG的质量状态。 tl; dr截至2015年末,它的"相当好",但没有加密质量。为了解决这个问题,这是上述解决方案的更新版本,该解决方案使用ES6,cryptoAPI和一些JS向导,我对此不以为然:

function uuidv4() {
  return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  )
}

console.log(uuidv4());

这只是一个简单的AJAX调用...

如果仍然有人感兴趣,这是我的解决方案。

在服务器端:

[WebMethod()]
public static string GenerateGuid()
{
    return Guid.NewGuid().ToString();
}

在客户端:

var myNewGuid = null;
PageMethods.GenerateGuid(
    function(result, userContext, methodName)
    {
        myNewGuid = result;
    },
    function()
    {
        alert("WebService call failed.");
    }
);

// RFC 4122
  //
  // A UUID is 128 bits long
  //
  // String representation is five fields of 4, 2, 2, 2, and 6 bytes.
  // Fields represented as lowercase, zero-filled, hexadecimal strings, and
  // are separated by dash characters
  //
  // A version 4 UUID is generated by setting all but six bits to randomly
  // chosen values
  var uuid = [
    Math.random().toString(16).slice(2, 10),
    Math.random().toString(16).slice(2, 6),

    // Set the four most significant bits (bits 12 through 15) of the
    // time_hi_and_version field to the 4-bit version number from Section
    // 4.1.3
    (Math.random() * .0625 /* 0x.1 */ + .25 /* 0x.4 */).toString(16).slice(2, 6),

    // Set the two most significant bits (bits 6 and 7) of the
    // clock_seq_hi_and_reserved to zero and one, respectively
    (Math.random() * .25 /* 0x.4 */ + .5 /* 0x.8 */).toString(16).slice(2, 6),

    Math.random().toString(16).slice(2, 14)].join('-');