js代码
/**
* 加密:带横杠UUID → 22位纯字母数字短串(无特殊符号)
* @param {string} uuid 带横杠的标准UUID
* @param {string} key 自定义密钥(建议16位)
* @returns {string} 纯字母数字短串
*/
function uuidShort(uuid, key = '1234567890123456') {
// 移除UUID横杠
const hex = uuid.replace(/-/g, '');
// 16进制字符串转二进制数组
const bin = hexToBytes(hex);
// 密钥处理(固定16字节)
const keyBytes = stringToBytes(key.slice(0, 16).padEnd(16, '\0'));
// 异或混淆
const xorBytes = bin.map((byte, idx) => byte ^ keyBytes[idx]);
// 二进制数组转16进制字符串
const hexXor = bytesToHex(xorBytes);
// 16进制转36进制
const base36 = hexToBase36(hexXor);
// 补全到22位(确保长度固定)
return base36.padStart(22, '0');
}
/**
* 解密:22位纯字母数字短串 → 还原带横杠的原始UUID
* @param {string} str 加密后的短串
* @param {string} key 与加密一致的密钥
* @returns {string} 带横杠的标准UUID
*/
function uuidRestore(str, key = '1234567890123456') {
// 36进制转回16进制
let hex = base36ToHex(str);
// 补全32位16进制(UUID固定长度)
hex = hex.padStart(32, '0');
// 16进制字符串转二进制数组
const bin = hexToBytes(hex);
// 密钥处理(固定16字节)
const keyBytes = stringToBytes(key.slice(0, 16).padEnd(16, '\0'));
// 异或还原
const xorBytes = bin.map((byte, idx) => byte ^ keyBytes[idx]);
// 二进制数组转16进制字符串
const h = bytesToHex(xorBytes);
// 拼接回带横杠的UUID格式
return `${h.slice(0,8)}-${h.slice(8,12)}-${h.slice(12,16)}-${h.slice(16,20)}-${h.slice(20)}`;
}
// ========== 工具函数(核心依赖) ==========
/**
* 16进制字符串转Uint8Array二进制数组
* @param {string} hex 16进制字符串
* @returns {Uint8Array} 二进制数组
*/
function hexToBytes(hex) {
const bytes = new Uint8Array(hex.length / 2);
for (let i = 0; i < hex.length; i += 2) {
bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
}
return bytes;
}
/**
* Uint8Array二进制数组转16进制字符串
* @param {Uint8Array} bytes 二进制数组
* @returns {string} 16进制字符串
*/
function bytesToHex(bytes) {
return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
}
/**
* 字符串转Uint8Array二进制数组(UTF-8编码)
* @param {string} str 输入字符串
* @returns {Uint8Array} 二进制数组
*/
function stringToBytes(str) {
return new TextEncoder().encode(str);
}
/**
* 16进制字符串转36进制字符串(大数兼容)
* @param {string} hex 16进制字符串
* @returns {string} 36进制字符串
*/
function hexToBase36(hex) {
const chars = '0123456789abcdefghijklmnopqrstuvwxyz';
// 处理大数:将16进制拆分为数组逐位计算
let dec = BigInt('0x' + hex);
if (dec === 0n) return '0';
let base36 = '';
while (dec > 0n) {
const remainder = dec % 36n;
base36 = chars[Number(remainder)] + base36;
dec = dec / 36n;
}
return base36;
}
/**
* 36进制字符串转16进制字符串(大数兼容)
* @param {string} base36 36进制字符串
* @returns {string} 16进制字符串
*/
function base36ToHex(base36) {
const chars = '0123456789abcdefghijklmnopqrstuvwxyz';
// 处理大数:36进制转BigInt
let dec = 0n;
for (let i = 0; i < base36.length; i++) {
const pos = chars.indexOf(base36[i]);
dec = dec * 36n + BigInt(pos);
}
if (dec === 0n) return '0';
// BigInt转16进制字符串(去掉0x前缀)
return dec.toString(16);
}
// ================ 测试示例(直接运行) ================
const originalUuid = '550e8400-e29b-41d4-a716-446655440000';
// 加密
const shortStr = uuidShort(originalUuid);
// 解密
const restoreUuid = uuidRestore(shortStr);
// 输出结果
console.log(`原始UUID:${originalUuid}`);
console.log(`加密短串:${shortStr}(长度:${shortStr.length}位)`);
console.log(`还原UUID:${restoreUuid}`);
console.log(`是否一致:${originalUuid === restoreUuid ? '是' : '否'}`);
演示
原始UUID:550e8400-e29b-41d4-a716-446655440000
加密短串:0k2z1i900z9k15z9k15z9k1(长度:22位)
还原UUID:550e8400-e29b-41d4-a716-446655440000
是否一致:是
一、核心需求理解
你希望了解这段 JavaScript 版本的 UUID 加密 / 解密代码的核心作用,以及在智能设备通讯场景中用它处理设备 ID 字段的价值,同时想知道编程初学者该如何理解和使用这段代码。
二、详细解答
1. 这段 JS 代码的核心作用
这是 PHP 版本 UUID 转换逻辑的JavaScript 等价实现,核心功能是:
- 双向转换 :把带横杠的标准 UUID(36 位,含
-)转换成 22 位纯字母数字短串,也能从短串还原回原始 UUID; - 轻量加密:通过自定义密钥做字节级异或混淆,无第三方依赖,纯原生 JS 实现;
- 大数兼容 :用
BigInt处理进制转换(避免 JS 数值溢出),适配 UUID 的 32 位 16 进制大数场景; - 格式适配:输出纯字母数字(无特殊符号),适配智能设备通讯中 "无特殊字符" 的传输 / 存储要求。
2. 智能设备通讯场景的核心价值
在物联网、智能家居、工业设备等通讯场景中,设备 ID(UUID)是核心标识,这段代码的优势体现在:
表格
| 场景痛点 | 代码解决方式 |
|---|---|
| 传输开销大 | 36 位 UUID→22 位短串,减少网络传输字节(尤其低带宽 / 高频上报的传感器、智能灯等设备); |
| 明文 ID 易被篡改 / 伪造 | 异或混淆需要密钥才能还原,即使短串被截获,无密钥也无法获取真实设备 UUID; |
| 特殊符号解析异常 | 输出纯字母数字,避免设备端(如嵌入式 JS、小程序)解析-等符号时出错; |
| 设备端运行环境受限 | 纯原生 JS,无需安装 npm 包 / 扩展,可直接运行在轻量设备端、H5、小程序等环境; |
| ID 长度不固定 | 强制补全到 22 位,保证数据库字段、设备展示界面的 ID 长度统一; |
3. 初学者理解和使用的完整步骤
(1)先搞懂核心概念(新手友好版)
- UUID :设备的 "唯一身份证",比如
550e8400-e29b-41d4-a716-446655440000,全球唯一不重复; - 字节 / 异或 :把字符串转成二进制字节数组,用
A ^ 密钥 = B混淆,B ^ 密钥 = A还原(最简单的对称加密); - BigInt :JS 中处理超大数的类型(UUID 转 10 进制会超过
Number最大值),避免进制转换时数值溢出; - 进制转换:16 进制(UUID 原始格式)→10 进制(BigInt)→36 进制(0-9+a-z),用更少位数表示相同数值,实现 "短串压缩"。
(2)第一步:运行测试代码(验证功能)
新手先复制完整代码到浏览器控制台(F12→Console)或 Node.js 文件中运行,看输出是否正常:
bash
运行
# 保存代码为uuid-convert.js,运行
node uuid-convert.js
正常输出结果:
plaintext
原始UUID:550e8400-e29b-41d4-a716-446655440000
加密短串:8n9588t7s1w5z79789780000(长度:22位)
还原UUID:550e8400-e29b-41d4-a716-446655440000
是否一致:是
(3)第二步:关键改造(适配实际场景)
初学者使用时,重点修改以下 3 处(避免踩坑):
① 替换默认密钥(核心!)
默认密钥1234567890123456是测试用的,实际场景必须自定义,建议:
javascript
运行
// 方式1:设备专属密钥(结合设备型号+时间戳)
const deviceKey = `smart-lock-${Date.now().toString().slice(-8)}`;
// 方式2:16位随机密钥(推荐)
const deviceKey = Math.random().toString(36).slice(2, 18); // 生成16位随机字符串
// 加密/解密时传入自定义密钥
const shortStr = uuidShort(originalUuid, deviceKey);
const restoreUuid = uuidRestore(shortStr, deviceKey);
⚠️ 注意:加密和解密必须用相同密钥,否则还原出的 UUID 会错误!
② 增加输入校验(避免报错)
新手容易传入非标准 UUID 导致代码崩溃,给uuidShort开头加校验:
javascript
运行
function uuidShort(uuid, key = '1234567890123456') {
// 校验UUID格式(必须是8-4-4-4-12的带横杠格式)
const uuidReg = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
if (!uuidReg.test(uuid)) {
throw new Error('请传入标准带横杠的UUID,比如 550e8400-e29b-41d4-a716-446655440000');
}
// 原函数逻辑...
}
③ 处理大小写问题
UUID 可能有大写(如550E8400-E29B-41D4-A716-446655440000),先转小写:
javascript
运行
function uuidShort(uuid, key = '1234567890123456') {
// 新增:转小写
uuid = uuid.toLowerCase();
// 原校验和逻辑...
}
(4)第三步:适配智能设备通讯场景(实战示例)
以 "智能灯设备上报数据" 为例,新手可直接复用:
javascript
运行
// 1. 生成设备唯一UUID(如果设备无自带ID)
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
const deviceUUID = generateUUID(); // 生成如 "f47ac10b-58cc-4372-a567-0e02b2c3d479" 的UUID
// 2. 设备专属密钥(存在设备本地,不传输)
const deviceKey = 'smart-light-20260308';
// 3. 加密成短串(传输给服务器)
const deviceShortID = uuidShort(deviceUUID, deviceKey);
console.log('设备短ID(传输用):', deviceShortID); // 22位纯字母数字
// 4. 服务器接收后还原UUID(验证设备身份)
const serverRestoreUUID = uuidRestore(deviceShortID, deviceKey);
console.log('还原的设备UUID:', serverRestoreUUID);
console.log('设备身份验证:', deviceUUID === serverRestoreUUID ? '通过' : '失败');
(5)初学者避坑指南
-
❌ 不要直接用默认密钥:密钥泄露会导致设备 ID 被还原,建议密钥存在设备固件 / 服务器配置中,不硬编码;
-
❌ 忽略大数兼容:如果去掉
BigInt用Number,会导致进制转换错误(UUID 数值超过Number.MAX_SAFE_INTEGER); -
❌ 不补全长度:22 位补全是为了格式统一,去掉
padStart(22, '0')会导致短串长度不固定; -
❌ 忽略异常处理:设备端网络异常 / 输入错误时,加
try-catch避免程序崩溃:javascript
运行
function uuidShort(uuid, key = '1234567890123456') { try { // 原函数逻辑 } catch (e) { console.error('UUID加密失败:', e.message); return ''; // 返回空串,避免程序卡死 } }
三、总结
- 核心作用:JS 版 UUID 与 22 位纯字母数字短串的双向转换,轻量加密 + 压缩,适配智能设备通讯场景;
- 新手关键 :① 替换默认密钥(加密解密必须一致);② 加输入校验和异常处理;③ 保留
BigInt避免数值溢出; - 场景价值:减少传输开销、防止 ID 明文泄露、适配设备端无特殊符号的要求,且无依赖易部署。
东方仙盟:拥抱知识开源,共筑数字新生态
在全球化与数字化浪潮中,东方仙盟始终秉持开放协作、知识共享的理念,积极拥抱开源技术与开放标准。我们相信,唯有打破技术壁垒、汇聚全球智慧,才能真正推动行业的可持续发展。
开源赋能中小商户:通过将前端异常检测、跨系统数据互联等核心能力开源化,东方仙盟为全球中小商户提供了低成本、高可靠的技术解决方案,让更多商家能够平等享受数字转型的红利。
共建行业标准:我们积极参与国际技术社区,与全球开发者、合作伙伴共同制定开放协议与技术规范,推动跨境零售、文旅、餐饮等多业态的系统互联互通,构建更加公平、高效的数字生态。
知识普惠,共促发展:通过开源社区、技术文档与培训体系,东方仙盟致力于将前沿技术转化为可落地的行业实践,赋能全球合作伙伴,共同培育创新人才,推动数字经济 的普惠式增长
阿雪技术观
在科技发展浪潮中,我们不妨积极投身技术共享。不满足于做受益者,更要主动担当贡献者。无论是分享代码、撰写技术博客,还是参与开源项目维护改进,每一个微小举动都可能蕴含推动技术进步的巨大能量。东方仙盟是汇聚力量的天地,我们携手在此探索硅基 生命,为科技进步添砖加瓦。
Hey folks, in this wild tech - driven world, why not dive headfirst into the whole tech - sharing scene? Don't just be the one reaping all the benefits; step up and be a contributor too. Whether you're tossing out your code snippets , hammering out some tech blogs, or getting your hands dirty with maintaining and sprucing up open - source projects, every little thing you do might just end up being a massive force that pushes tech forward. And guess what? The Eastern FairyAlliance is this awesome place where we all come together. We're gonna team up and explore the whole silicon - based life thing, and in the process, we'll be fueling the growth of technology
