文章介绍了如何为上传到CDN平台的文件生成唯一文件名,探讨了不同的命名方法,并提出了一种基于时间戳和随机数的优化方案,以确保文件名的唯一性和简短性。文章还介绍了唯一命名方式的几种方法,包括使用时间戳+随机数、文件MD5值、UUID等,并指出了每种方式的优缺点。最终方案是基于时间戳和随机数,通过优化方式减少文件名字符长度至7位,且可以100%保证唯一性。
文章介绍了多种文件命名方式,包括使用时间戳+随机数、文件MD5值、UUID等,并分析了每种方式的优缺点。
文章提出了一种基于时间戳和随机数的优化方案,通过转换为62进制、优化时间戳计算等方式,将文件名字符长度减少至7位,且可以100%保证唯一性。
作者呼吁读者从文章中获取收获,并鼓励点赞和关注下一期内容。
前言
介绍了如何为上传到 CDN 平台的文件生成一个唯一的文件名,并探讨了几种不同的命名方法,最终提出了一种基于时间戳和随机数的优化方案,以确保文件名的唯一性和简短性。今日前端早读课文章由 @陈杰分享,公号:Goodme 前端团队授权分享。
正文从这开始~~
背景
古茗内部有一个 CDN 文件上传平台,用户在平台上传文件时,会将文件上传至阿里云 OSS 对象存储,并将 OSS 链接转换成 CDN 链接返回给用户,即可通过 CDN 链接访问到文件资源。我们对 CDN 文件的缓存策略是持久化强缓存 (
Cache-Control: public, max-age=31536000
),这就要求所有上传文件的文件名都是唯一的,否则就有文件被覆盖的风险。有哪些方式可以保证文件名全局唯一?
唯一命名方式
方式一:使用时间戳 + 随机数
这是我们最容易想到的一种方式:
const name = Date.now() + Math.random().toString().slice(2, 6);
// '17267354922380490'
使用时间戳,加上 4 位随机数,已经可以 99.99999% 保证不会存在文件名重复。可以稍微优化一下:
const name = Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
// 'm191x7bii63s'
将时间戳和随机数分别转换成 36 进制,以减少字符串长度。通过上面一步优化可以将字符长度从 17 位减少至 12 位。
使用时间戳 + 随机数作为文件名的优势是简单粗暴,基本上可以满足述求;但是有极小概率存在文件名冲突的可能。
方式二:使用文件 MD5 值
生成文件的 MD5 Hash 摘要值,在 node 中代码示例如下:
const crypto = require('crypto');
const name = crypto.createHash('md5').update([file]).digest('hex');
// 'f668bd04d1a6cfc29378e24829cddba9'
文件的 MD5 Hash 值可以当成文件指纹,每个文件都会生成唯一的 hash 值(有极小的概率会 hash 碰撞,可以忽略)。使用 MD5 Hash 值作为文件名还可以避免相同文件重复上传;但是缺点是文件名较长。
方式三:使用 UUID
UUID (通用唯一识别码) 是用于计算机体系中以识别信息的一个标识符,重复的概率接近零,可以忽略不计。
生成的 UUID 大概长这样:279e573f-c787-4a84-bafb-dfdc98f445cc。
使用 UUID 作为文件名的缺点也是文件名较长。
【第3248期】提升用户体验的UUID设计策略
最终方案
从上述的几种命名方式可以看出,每种方式都有各种的优缺点,直接作为 OSS 的文件命名都不是很满意(期望 CDN 链接尽可能简短)。所以我们通过优化时间戳 + 随机数方式来作为最终方案版本。
本质上还是基于时间戳、随机数 2 部分来组成文件名,但是有以下几点优化:
-
由于 CDN 链接区分大小写,可以充分利用 数字 + 大写字母 + 小写字母(一共 62 个字符),也就是可以转成 62 进制,来进一步缩短字符长度
-
时间戳数字的定义是,当前时间减去 1970-01-01 的毫秒数。显然在 2024 年的今天,这个数字是非常大的。对此,可以使用 当前时间减去 2024-01-01 的毫秒数 来优化,这会大幅减少时间戳数字大小(2024-01-01 这个时间点是固定的,而且必须是功能上线前的一个时间点,确保不会减出负数)
示例代码如下:
/**