Как создать GUID / UUID в JavaScript?
Как можно генерировать GUIDы (глобально уникальные идентификаторы) в JavaScript, которые содержат не менее 32 символов и остаются в диапазоне ASCII для обеспечения совместимости при их передаче?
Какие браузерно-совместимые методы доступны для генерации GUID/UUID, и насколько надежны встроенные генераторы случайных чисел в плане случайности и инициализации?
Содержание
- Современные методы браузеров
- Пользовательские реализации
- Кросс-браузерные решения
- Надежность генератора случайных чисел
- Лучшие практики и рекомендации
Современные методы браузеров
crypto.randomUUID()
Самый простой метод, доступный в современных браузерах, — это функция crypto.randomUUID(), которая генерирует UUID версии 4 в соответствии с RFC 4122:
const uuid = crypto.randomUUID();
// Пример: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
Этот метод produces строку из 36 символов, включая дефисы. Если вам нужна 32-символьная версия без дефисов:
const uuid = crypto.randomUUID().replace(/-/g, '');
// Пример: "f47ac10b58cc4372a5670e02b2c3d479"
crypto.getRandomValues()
Для большего контроля над процессом генерации можно использовать crypto.getRandomValues() с пользовательской реализацией:
function generateUUID() {
const array = new Uint32Array(4);
crypto.getRandomValues(array);
return Array.from(array, dec =>
('0' + dec.toString(16).substr(-2)).substr(-2)
).join('');
}
// Пример: "4a3b2c1d5e6f7890abcdef1234567890"
Этот подход дает вам 32-символьную шестнадцатеричную строку напрямую.
Пользовательские реализации
Метод для старых браузеров
Для сред без поддержки crypto.randomUUID() можно реализовать собственный генератор GUID:
function generateCustomGUID() {
return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
Реализация на основе временной метки
Для приложений, требующих последовательной уникальности:
function generateTimestampGUID() {
const timestamp = Date.now().toString(16);
const randomPart = Math.floor(Math.random() * 0xFFFFFFFF).toString(16);
return (timestamp + randomPart).padEnd(32, '0').substr(-32);
}
Кросс-браузерные решения
Подход с полифилом
Чтобы обеспечить совместимость со всеми браузерами, можно создать полифил, который определяет лучший доступный метод:
function generateGUID() {
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
return crypto.randomUUID().replace(/-/g, '');
} else if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
return generateUUIDWithCrypto();
} else {
return generateCustomGUID();
}
}
function generateUUIDWithCrypto() {
const array = new Uint32Array(4);
crypto.getRandomValues(array);
return Array.from(array, dec =>
('0' + dec.toString(16).substr(-2)).substr(-2)
).join('');
}
function generateCustomGUID() {
return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
Решения на основе библиотек
Рассмотрите возможность использования проверенных библиотек, таких как:
- uuid: популярный npm-пакет для генерации UUID
- crypto-uuid: легковесная реализация с фокусом на совместимость с браузерами
npm install uuid
import { v4 as uuidv4 } from 'uuid';
const uuid = uuidv4().replace(/-/g, '');
Надежность генератора случайных чисел
Безопасность API Crypto браузера
Метод crypto.getRandomValues() предоставляет криптографически безопасные случайные числа, которые:
- Правильно инициализированы: Используют системные источники энтропии
- Непредсказуемы: Подходят для приложений, чувствительных к безопасности
- Кросс-платформенные: Последовательное поведение в разных браузерах
Ограничения Math.random()
Встроенная функция Math.random() имеет несколько ограничений:
- Не криптографически безопасна: Могут проявляться предсказуемые паттерны
- Зависит от реализации: Разные браузеры используют разные алгоритмы
- Нет контроля инициализации: Нельзя инициализировать для воспроизводимости в тестах
Таблица сравнения
| Метод | Безопасность | Поддержка браузеров | Производительность | Случай использования |
|---|---|---|---|---|
crypto.randomUUID() |
Высокая | Современные браузеры | Отличная | Производственные приложения |
crypto.getRandomValues() |
Высокая | Все современные браузеры | Хорошая | Пользовательские реализации |
На основе Math.random() |
Низкая | Все браузеры | Быстрая | Некритичные приложения, тестирование |
Лучшие практики и рекомендации
Производительность
- Пакетная генерация: По возможности генерируйте несколько UUID сразу
- Эффективность памяти: В приложениях с критичной производительностью используйте повторно буферные объекты
- Избегайте конкатенации строк: Используйте объединение массивов для лучшей производительности
Вопросы безопасности
// Пример безопасной реализации
function generateSecureUUID() {
if (typeof crypto === 'undefined' || !crypto.getRandomValues) {
throw new Error('Генератор безопасных случайных чисел недоступен');
}
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
// Установка версии (4) и битов варианта
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
}
Тестирование и валидация
Всегда валидируйте генерацию UUID:
function isValidUUID(uuid) {
const regex = /^[0-9a-f]{32}$/i;
return regex.test(uuid) && uuid.length === 32;
}
// Тестирование генерации
const testUUID = generateGUID();
console.log(isValidUUID(testUUID)); // Должно быть true
Источники
- Спецификация Web Crypto API - MDN
- Спецификация UUID - RFC 4122
- Генерация случайных чисел в JavaScript - MDN
- Руководство по совместимости браузеров - Can I Use
Заключение
Генерация GUID/UUID в JavaScript требует выбора правильного метода в зависимости от требований совместимости с браузерами и потребностей в безопасности. Современные приложения должны предпочитать crypto.randomUUID() за его простоту и безопасность, в то время как устаревшие системы могут использовать пользовательские реализации с соответствующими резервными вариантами. Всегда отдавайте приоритет Web Crypto API для приложений, чувствительных к безопасности, и валидируйте сгенерированные UUID, чтобы убедиться, что они соответствуют требованию 32-символьной ASCII-строки. Для критически важных приложений рассмотрите использование проверенных библиотек, которые были тщательно протестированы на множестве браузеров и платформ.