ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Nano ID 完全指南:118 字节的 JavaScript 安全 URL 友好 ID 生成器

Nano ID 完全指南:118 字节的 JavaScript 安全 URL 友好 ID 生成器 开发工具【免费下载链接】nanoidA tiny (118 bytes), secure, URL-friendly, unique string ID generator for JavaScript项目地址https://gitcode.com/gh_mirrors/na/nanoid点击查看免费下载导读本文以 Nano ID 官方文档README.ru.md为主线结合仓库源码index.js、index.browser.js、non-secure/index.js与测试用例系统讲解这个以 118 字节体积著称的 JavaScript 唯一 ID 生成器的设计原理、安全模型与全部 API 用法。读完本文你将掌握nanoid()、customAlphabet()、customRandom()、nanoid/non-secure四大核心接口的完整用法理解其抗碰撞与均匀分布的底层算法并能在 React、React Native、PouchDB、终端与 TypeScript 场景中正确落地使用。Nano ID 是什么Nano ID 是一个轻量、安全、URL 友好的 JavaScript 唯一字符串 ID 生成器。它由 Andrey Sitnik 开发当前仓库版本为 6.0.1见 package.json。其核心特性如下极轻量最小化 Brotli 压缩后仅118 字节且零依赖。这一数字由仓库中的size-limit配置强制约束见 package.json 中limit: 118 B的声明。快速官方文档声明其比 Node.js 原生crypto.randomUUID()快约 50%。安全默认使用硬件随机数生成器Node.js 的crypto模块与浏览器 Web Crypto API可安全用于机器集群。短 ID采用比 UUID 更大的字母表A-Za-z0-9_-共 64 个字符将同等随机性压缩进更短的字符串——默认 21 个字符而 UUID 为 36 个字符。跨平台支持现代浏览器、IE配合 Babel、Node.js 与 React Native且已被移植到 20 多种编程语言。最基本的用法只有一行import { nanoid } from nanoid model.id nanoid() // V1StGXR8_Z5jdHi6B-myT与 UUID v4 的对比Nano ID 与随机型 UUID v4 属于同类方案二者的 ID 随机位数相当Nano ID 为 126 位UUID 为 122 位因此碰撞概率重复生成相同 ID 的可能性也非常接近要使重复概率接近十亿分之一需要生成 103 万亿个 ID。但二者有两点重要差异更宽的字母表Nano ID 将同等数量的随机位打包进更短的字符串21 字符 vs 36 字符。更快的速度Nano ID 快于crypto.randomUUID与uuid/v4。性能基准官方文档提供了 test/benchmark.js 的运行输出示例读者可在自己的环境中通过node ./test/benchmark.js复现$ node ./test/benchmark.js nope-id 20,386,830 ops/sec nanoid 20,434,827 ops/sec customAlphabet 20,544,476 ops/sec crypto.randomUUID 12,865,759 ops/sec uuid v4 7,930,104 ops/sec napi-rs/uuid 5,573,171 ops/sec uid/secure 6,308,267 ops/sec lukeed/uuid 5,278,597 ops/sec nanoid for browser 311,497 ops/sec secure-random-string 301,667 ops/sec uid-safe.sync 297,815 ops/sec Non-secure: uid 20,286,757 ops/sec nanoid/non-secure 2,397,594 ops/sec rndm 2,445,462 ops/sec需要说明的是上表是 README 记录的环境示例具体数值会随硬件与 Node 版本变化但crypto.randomUUID、uuid v4等知名方案均被 test/benchmark.js 列为对照项Nano ID 处于同类第一梯队这一点在源码层面是成立的。性能优势的根源在于 index.js 的两类优化一是customAlphabet使用预生成字符串池每次申请一批随机字节、一次Buffer#toString()转换后续 ID 只需廉价的substring二是按需填充避免频繁的系统熵调用。安全模型不可预测性与可预测的Math.random()不同Nano ID 在 Node.js 中使用crypto模块、在浏览器中使用 Web Crypto API二者都对接硬件随机数生成器。对应实现见 index.jsNode 端通过crypto.getRandomValues填充Buffer与 index.browser.js浏览器端直接crypto.getRandomValues(new Uint8Array(bytes))。Node 端还处理了一个边界crypto.getRandomValues单次请求上限为 65536 字节因此fillRandom会分块填充更大的缓冲区见 index.js。均匀分布拒绝采样算法许多自制 ID 生成器常犯random % alphabet的错误导致部分字符出现概率偏高。当随机字节的取值范围256不能被字母表长度整除时取模会使空间使用不均匀攻击者枚举 ID 所需的时间会比预期更短。Nano ID 在 index.js 中实现了拒绝采样来消除这种偏差计算safeByteCutoff 256 - (256 % alphabet.length)只接受小于该阈值的随机字节从而保证每个字符等概率当字母表长度为 2 的幂时如 64 字符的urlAlphabet直接用 mask位运算替代取模既无偏差又更快为了减少被拒绝字节带来的额外系统调用step Math.ceil((1.6 * 256 * defaultSize) / safeByteCutoff)中的系数1.6是经基准测试选出的魔法数字用于预取足够的随机字节覆盖拒绝损耗。分布均匀性由 test/index.test.js 中的has flat distribution用例直接验证统计 10 万个 ID 后断言 64 个字符全部出现且各字符频率的归一化差异不超过 0.05。上图img/distribution.png展示了默认 64 字符字母表下各符号的出现频率64 个符号全部被覆盖且频率接近直观印证了分布均匀性测试的结果。其他安全相关事实文档完备Nano ID 的所有技巧在源码注释中都有详细说明例如 index.js 中关于拒绝采样、字符串池与1.6系数来源的注释。漏洞上报若发现安全漏洞官方文档指引联系 Tidelift 安全团队由其跟进修复并通知用户。安装与引入npm 安装npm install nanoid当前仓库版本为 6.0.1且package.json中声明了type: module因此默认通过 ESM 语法导入import { nanoid } from nanoid注意仓库的engines字段要求 Node.js^22 || ^24 || 26见 package.json使用前请确认环境版本。通过 JSR 安装JSRnpx jsr add sitnik/nanoid该包可用于 Node.js、Deno、Bun只需将导入路径中的nanoid替换为sitnik/nanoidimport { nanoid } from sitnik/nanoidDeno 用户可用deno add jsr:sitnik/nanoid安装或直接import jsr:sitnik/nanoid导入。CDN 快速原型不想安装时可以从 CDN 加载适合快速原型验证import { nanoid } from https://cdn.jsdelivr.net/npm/nanoid/nanoid.js官方文档明确提醒不要在生产站点使用这种方式它会严重拖慢页面加载速度。API 详解默认情况下Nano ID 使用 URL 安全字符集A-Za-z0-9_-默认 ID 长度为 21 字符使碰撞概率与 UUID v4 相当。import { nanoid } from nanoid model.id nanoid() // V1StGXR8_Z5jdHi6B-myT函数也接受可选的长度参数nanoid(10) // IRFa-VaY2b调整长度时务必用官方文档提供的碰撞概率计算器评估风险。关于边界的实现细节nanoid(0)返回空字符串负数或超长尺寸会抛出异常参见 index.js 的Wrong ID size校验及 test/index.test.js 的对应测试。自定义字母表或长度customAlphabetcustomAlphabet(alphabet, defaultSize)返回一个可复用的生成器函数import { customAlphabet } from nanoid const nanoid customAlphabet(1234567890abcdef, 10) user.id nanoid() // 4f90d13a42非安全版本同样支持后文详述import { customAlphabet } from nanoid/non-secure const nanoid customAlphabet(1234567890abcdef, 10) user.id nanoid()使用要点字母表不得超过 256 个字符否则无法保证 ID 的不可预测性。这一约束在 index.d.ts 的类型注释与 index.js 的实现中均有体现——当字母表非法或含有多字节字符如俄语字母абвгд时实现会自动降级到通用的customRandom路径而测试 test/index.test.js 确认了这两种情况均可正常工作。长度可在调用时覆盖除了在工厂函数中设定默认长度每次调用生成器时还可以临时指定import { customAlphabet } from nanoid const nanoid customAlphabet(1234567890abcdef, 10) model.id nanoid(5) // f01a2建议在使用自定义字母表前后用官方碰撞计算器校验风险需要现成字母表时可参考nanoid-dictionary项目收录的众多流行方案。底层优化Node 端的customAlphabetindex.js为单字节字母表实现了字符串池快路径——将字母表字符码写入Uint8Array随机字节直接映射为字符码并写入Buffer最终以一次toString(latin1)生成整个池后续每个 ID 只是一次substring。池的大小按首次请求尺寸起步并几何增长target * 16上限为POOL_MAX 65536 / 2避免短生命周期生成器为完整池买单。这也是它在基准中达到约 2054 万 ops/sec 的原因之一。自定义随机生成器customRandomcustomRandom(alphabet, defaultSize, random)允许同时替换字母表与随机字节源。例如为了测试的可重复性可以接入带种子的生成器import { customRandom } from nanoid const rng seedrandom(seed) const nanoid customRandom(abcdef, 10, size { return new Uint8Array(size).map(() 256 * rng()) }) nanoid() // fbaefaadeb第三个参数random回调必须接收目标字节数组的长度并返回装满随机数的数组每个字节取值 0–255。类型签名见 index.d.ts。如果只想替换随机源、保留 URL 友好字母表可以直接复用urlAlphabet导出const { customRandom, urlAlphabet } require(nanoid) const nanoid customRandom(urlAlphabet, 10, random)urlAlphabet的定义位于 url-alphabet/index.js64 个字符的字符串useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict其字符顺序专门为 gzip/brotli 压缩效果做过优化。测试 test/index.test.js 断言它包含 64 个符号且无重复customRandom对任意随机源的映射正确性则由supports generator、supports power-of-two alphabets等用例test/index.test.js覆盖。非安全版本nanoid/non-secure安全版本依赖硬件随机源若运行环境没有对应 API可以切换到非安全版本import { nanoid } from nanoid/non-secure const id nanoid() // Uakgb_J5m9g-0JDMbcJqLJ必须注意两点原文明确强调可预测性风险ID 可被预测可能被用于攻击系统更慢的性能非安全版本反而比安全版本慢——基准中nanoid/non-secure约 240 万 ops/sec远低于安全版的 2043 万 ops/sec。因为安全版在 index.js 中通过字符串池与Buffer#toString批处理大幅摊薄了成本而 non-secure/index.js 的实现是逐字符Math.random()拼接见其第 13、26 行的id alphabet[(Math.random() * alphabet.length) | 0]。因此仅在确实没有硬件随机 API 的环境中才应使用非安全版本。它的体积也更小非安全版nanoid为 93 字节见 package.json。实战指南React不要用 nanoid 生成 JSX key在渲染过程中调用nanoid()会为每次渲染生成不同的key严重损害 React 的协调性能。以下做法是错误的function Todos({ todos }) { return ( ul {todos.map(todo ( li key{nanoid()} { } /* НЕ ДЕЛАЙТЕ ТАК */ {todo.text} /li ))} /ul ) }需要关联input与label时应改用 React 18 引入的useIdHook。React Native需要 polyfillReact Native 没有内置硬件随机数生成器需先安装并导入react-native-get-random-values纯 React Native 与 Expo 39 均适用阅读react-native-get-random-values的文档并安装在导入 Nano ID之前先导入该 polyfillimport react-native-get-random-values import { nanoid } from nanoid此外package.json 的react-native字段会把index.js映射到index.browser.js即 React Native 环境实际运行的是基于 Web Crypto API 的浏览器实现。PouchDB 与 CouchDB避免_开头PouchDB/CouchDB 不允许文档 ID 以_开头而 Nano ID 偶尔可能生成这样的 ID。解决办法是添加前缀db.put({ _id: id nanoid(), … })终端npx 直接生成只要系统装了 Node.js即可在终端直接生成唯一 IDnpx会自动下载 Nano ID$ npx nanoid npx: installed 1 in 0.63s LZfXLFzPPR4NNrgjlWDxn可用--size或-s指定长度$ npx nanoid --size 10 L3til0JS4z用--alphabet或-a指定字母表此时--size必填$ npx nanoid --alphabet abc --size 15 bccbcabaabaccabCLI 的完整行为由 test/bin.test.js 验证默认输出 21 字符、--size/--alphabet生效、未知参数报Unknown argument、非正整数尺寸报Size must be positive integer并支持--help与--version。TypeScript不透明字符串类型Nano ID 的生成函数支持泛型参数可将返回的字符串收窄为不透明opaque类型从而在类型层面隔离不同用途的 IDdeclare const userIdBrand: unique symbol type UserId string { [userIdBrand]: true } // 使用显式类型参数 mockUser(nanoidUserId()) interface User { id: UserId name: string } const user: User { // 自动推导为 UserId 类型 id: nanoid(), name: Alice }对应的泛型签名定义在 index.d.tsexport function nanoidType extends string(size?: number): Type以及 index.d.ts、index.d.ts 中。其他编程语言为了让服务器与客户端按同一套方案生成 IDNano ID 已被移植到 20 多种语言包括C#、C、Clojure/ClojureScript、ColdFusion/CFML、Crystal、Dart/Flutter、Elixir、Gleam、Go、Haskell、Haxe、Janet、Java、Kotlin、MySQL/MariaDB、Nim、Perl、PHP、Python含字典包、PostgresRust 扩展与纯 pgSQL 两种实现、R、Ruby、Rust、Swift、Unison、V、Zig。其余环境可退而求其次使用终端方式。周边工具官方文档推荐三个配套工具ID 长度计算器根据 ID 发放频率与所需可靠度推荐最优 ID 长度。nanoid-dictionary收录大量现成字母表可直接配合customAlphabet使用。nanoid-good保证生成的随机 ID 中不出现不雅词汇。小结Nano ID 用 118 字节实现了安全、快速、URL 友好的唯一 ID 生成拒绝采样算法保证分布均匀字符串池优化带来极高的吞吐customAlphabet/customRandom提供完整的定制能力non-secure子路径覆盖无硬件随机源的环境。无论你是为数据库主键、短链接、会话令牌还是集群去重生成 IDindex.js 及其配套的 index.d.ts、test/index.test.js 都是值得深入研读的参考实现。赞分享开发工具【免费下载链接】nanoidA tiny (118 bytes), secure, URL-friendly, unique string ID generator for JavaScript项目地址https://gitcode.com/gh_mirrors/na/nanoid点击查看免费下载相关推荐NanoID: 简洁而安全的URL友好唯一字符串ID生成器NanoID: 简洁而安全的URL友好唯一字符串ID生成器 一、项目介绍 NanoID 是一款轻量级 大小仅124字节 、安全且友好的唯一字符串ID生成库专为开发工具Nano ID完整指南终极JavaScript字符串ID生成器教程Nano ID完整指南终极JavaScript字符串ID生成器教程 Nano ID是一个小巧、安全、URL友好的JavaScript字符串ID生成器专为现代开发工具短ID生成器shortid终极指南7-14字符URL友好ID解决方案短ID生成器shortid终极指南7 14字符URL友好ID解决方案 短ID生成器shortid是一个革命性的URL友好唯一ID生成器专为现代Web应用设计后端上一篇Snap Camera 镜头全部消失SnapCameraPreservation 新手自救终极指南5 大高频故障一次排查清楚下一篇Chatterbox模型精度优化指南FP32、FP16、INT8的全面对比创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表