Генерация уникальных идентификаторов с помощью Web Crypto API
Каждый фронтенд-разработчик рано или поздно сталкивается с этой проблемой: вам нужен уникальный идентификатор для данных на стороне клиента, но серверного ID ещё нет. Возможно, вы создаёте список задач, управляете полями формы или отслеживаете элементы до их сохранения. Вам нужно надёжное решение, и оно нужно прямо сейчас.
Хорошая новость? Современные браузеры поставляются со встроенным решением. Web Crypto API предоставляет crypto.randomUUID() — простой и безопасный способ генерации уникальных идентификаторов в браузере без установки каких-либо библиотек.
Ключевые моменты
crypto.randomUUID()генерирует криптографически безопасные UUID версии 4, соответствующие RFC, нативно в браузере без каких-либо зависимостей.- Всегда генерируйте идентификаторы во время создания объекта, а не в процессе рендеринга.
- Метод требует безопасного контекста (HTTPS или
localhost). - Для сред, не поддерживающих
crypto.randomUUID(), используйтеcrypto.getRandomValues()в качестве лёгкой альтернативы.
Почему crypto.randomUUID() должен быть вашим выбором по умолчанию
Метод crypto.randomUUID() генерирует UUID версии 4 согласно RFC 9562 (ранее RFC 4122), используя криптографически безопасный генератор случайных чисел. Результат выглядит следующим образом:
550e8400-e29b-41d4-a716-446655440000
Это строка из 36 символов со 122 битами случайности. Вероятность коллизии астрономически мала — вам потребовалось бы генерировать миллиард UUID в секунду в течение примерно 85 лет, чтобы достичь 50% вероятности хотя бы одной коллизии.
Вот насколько это просто:
function generateId() {
return crypto.randomUUID()
}
const newItem = { id: generateId(), label: 'My item' }
Этот метод работает во всех современных браузерах (Chrome 92+, Firefox 95+, Safari 15.4+), выполняется в Web Workers и не требует зависимостей.
Требование безопасного контекста
Один важный момент: crypto.randomUUID() работает только в безопасных контекстах. Это означает HTTPS в продакшене или localhost во время разработки. Если вы тестируете через обычный HTTP на домене, отличном от localhost, метод будет недоступен.
Это требование существует потому, что Web Crypto API предоставляет криптографические примитивы, которые не должны быть доступны в небезопасных окружениях.
Почему старые подходы недостаточно хороши
До того, как crypto.randomUUID() стал широко доступен, разработчики часто прибегали к альтернативам, которые кажутся разумными, но имеют реальные проблемы.
Math.random() не является криптографически безопасным. Его результат может быть предсказуемым, а коллизии встречаются гораздо чаще, чем можно ожидать в продакшн-приложениях.
Временные метки (например, Date.now()) не работают, когда несколько идентификаторов генерируются в одну и ту же миллисекунду — обычный сценарий в циклах или пакетных операциях.
Самодельные генераторы, комбинирующие временные метки со случайными числами, лучше, но они заново изобретают уже решённую проблему с меньшей строгостью, чем предоставляет платформа нативно.
Для безопасной генерации идентификаторов на стороне клиента crypto.randomUUID() — очевидный выбор.
Discover how at OpenReplay.com.
Практические аспекты для фронтенда
Генерируйте один раз, сохраняйте немедленно
Самая распространённая ошибка — генерация идентификаторов во время циклов рендеринга. Вместо этого создавайте ID при создании объекта и сохраняйте его:
// ✓ Правильно: ID генерируется во время создания
function addItem(label) {
return { id: crypto.randomUUID(), label }
}
// ✗ Неправильно: ID генерируется во время рендеринга
items.map(item => <li key={crypto.randomUUID()}>{item.label}</li>)
Генерация нового UUID при каждом рендере сводит на нет цель стабильных ключей. React, например, использует ключи для отслеживания элементов между повторными рендерами. Новый ключ каждый раз вызывает ненужное удаление и пересоздание DOM.
SSR и браузерные окружения
Если вы используете серверный рендеринг, crypto.randomUUID() доступен в Node.js 19+ и последних версиях других сред выполнения. Для более старых версий Node или особых случаев проверяйте доступность перед вызовом:
const id = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
? crypto.randomUUID()
: fallbackGenerator()
Лёгкая стратегия запасного варианта
Для окружений, где crypto.randomUUID() недоступен, crypto.getRandomValues() имеет более широкую поддержку (включая Node.js 16+) и может генерировать UUID без библиотек:
function fallbackUUID() {
const bytes = crypto.getRandomValues(new Uint8Array(16))
bytes[6] = (bytes[6] & 0x0f) | 0x40 // Version 4
bytes[8] = (bytes[8] & 0x3f) | 0x80 // Variant 10
const hex = [...bytes].map(b => b.toString(16).padStart(2, '0')).join('')
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`
}
Это вручную устанавливает биты версии и варианта для создания валидного UUID v4, используя тот же криптографически безопасный источник случайности под капотом.
Когда библиотеки всё ещё имеют смысл
Хотя crypto.randomUUID() покрывает большинство случаев, вы можете обратиться к библиотеке вроде uuid или nanoid, когда вам нужны:
- UUID версий, отличных от v4 (v1, v5, v7)
- Более короткие идентификаторы для URL или отображения пользователям
- Гарантированная кроссплатформенная совместимость со старыми средами выполнения
Но для стандартной безопасной генерации идентификаторов на стороне клиента нативный API должен быть вашей отправной точкой.
Заключение
crypto.randomUUID() предоставляет вам соответствующие RFC, криптографически безопасные UUID без каких-либо зависимостей. Генерируйте идентификаторы во время создания объекта, а не во время рендеринга. Используйте HTTPS в продакшене. Для особых случаев используйте запасной вариант с crypto.getRandomValues(). Браузер уже имеет всё, что вам нужно — используйте это.
Часто задаваемые вопросы
Да, UUID v4, генерируемые crypto.randomUUID(), подходят в качестве первичных ключей. 122 бита криптографической случайности делают коллизии практически невозможными. Однако имейте в виду, что случайные UUID могут вызывать фрагментацию индексов в некоторых базах данных. Если производительность вставки важна в масштабе, рассмотрите UUID v7, который упорядочен по времени, хотя для этого потребуется библиотека.
Он требует безопасного контекста, потому что Web Crypto API предоставляет криптографические примитивы. Браузеры ограничивают их использование HTTPS и localhost, чтобы предотвратить атаки типа man-in-the-middle от вмешательства в криптографические операции. Во время локальной разработки на localhost он работает без HTTPS. В продакшене вам нужен действительный TLS-сертификат.
Да. Объект crypto и его метод randomUUID доступны в Web Workers, Service Workers и Shared Workers, если контекст безопасен. Это делает удобным генерацию идентификаторов в фоновых потоках без необходимости обмена данными с основным потоком для создания ID.
crypto.randomUUID() производит стандартные UUID v4 длиной 36 символов, используя встроенный в браузер криптографический генератор случайных чисел. nanoid генерирует более короткие, URL-дружественные идентификаторы с настраиваемым алфавитом и длиной, и работает в большем количестве окружений из коробки. Выбирайте randomUUID для соответствия стандартам и отсутствия зависимостей. Выбирайте nanoid, когда вам нужны компактные идентификаторы или более широкая поддержка сред выполнения.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.