【互联网老饕小知识】为什么文件要添加一个 hash 后缀?

在互联网冲浪时,我们会经常看到带有 hash 的文件名,例如:

app.9f8e7d.js  
style.a13c22.css  
audio-20240201-7c91bf.mp3

表面上只是多了几位随机字符,但它却是很少公开讨论的开发经验:

让系统能够可靠、准确地获取文件的最新版本。

为什么需要这样做?在我的认知里有三层影响因素。


一、缓存系统

浏览器、代理服务器、CDN 都遵循相同的缓存行为:

URL 不变,就认为文件没有变化。

例如,你更新了一个脚本:

script.js   // 更新了一些内容但是文件名不变

但如果仍然使用同样的文件名,客户端通常会:

  • 继续使用本地缓存
  • 不重新请求服务器
  • 即使请求,也可能被中间 CDN 返回旧版本

这一行为完全符合 HTTP 标准,但对开发者而言会造成版本错乱。

因此,一个最直接且可靠的方式是:

将文件内容的 hash 值写入文件名,使 URL 与内容强绑定。

当文件内容变更时,hash 自然会变化,URL 随之变化,

所有缓存系统都会立刻识别为“全新资源”。

二、hash 是“最稳定的版本编号”

你当然可以手动给文件加时间戳或版本号,例如:

script_v2.js
script_20240201.js

但这些方式的问题是依赖人工维护,在自动化构建体系中不够稳健。

相比之下,“内容 hash”具备天然优势:

  • 内容相同 → hash 不变
  • 内容改变 → hash 自动变化
  • 构建工具可以自动生成
  • 不依赖人工操作
  • 兼容所有缓存策略

因此,包含 hash 的文件名是一种确定性版本管理,具有可重复构建的特性。
其实如果大家玩 NAS 会发现在同步一些网盘文件时,会频繁发生删除动作,本质上也是网盘内部的文件 hash 值变更导致的误判。

三、在中国网络环境中的一个特殊原因

除了常规的浏览器、CDN 缓存外,中国网络环境里还存在一种历史遗留机制:

部分运营商早期部署的透明缓存

这种缓存系统有一个典型特征:

  • 不认真处理 HTTP 头部中的缓存指令
  • 不检查 ETag、Last-Modified
  • 倾向于用“文件名 + URL”作为缓存键
  • 文件名不变 → 即使内容更新也不会回源获取

这意味着:

如果你更新了文件但文件名没变,运营商可能继续向用户返回旧版本。

这种行为在技术标准上并不理想,但它曾在部分网络环境中存在较长时间,因此许多互联网团队形成了一个经验法则:

只要希望确保内容绝对刷新,就必须改变 URL,而添加 hash 是最标准、最可自动化的实现方式。

现代 HTTPS 大幅削弱了透明缓存的影响,但这一做法仍被保留,并成为 Web 构建体系的默认模式。

22 个赞


随手打开f12一看还真是这样

1 个赞

js 主要是对抗浏览器缓存和 cdn

太强了,大佬

又向大佬学到了新知识

1 个赞

来了 大帅哥

互相学习 互相学习

学费了,感谢分享

:thinking:我记得以前没有做js文件hash的时候,增加 ?v=时间戳 ,也是可以强制刷新的,应该是一样的逻辑吧

1 个赞

这个方案可以 但是杜绝不了 CDN 厂商和运营商缓存策略的问题
或者换句话说,他们没遵循相关协议开发导致 ?v= 不一定有效,因此加 hash 后缀更万金油一些

2 个赞

昨天听一个播客时就提到有运营商的问题,没想到今天在这儿也看到了,太巧了

科技大乱炖吧? 我昨天骑车的时候正好在听,因此写了一下。看我贴的图,就是他们的 rss hhh

哈哈哈哈,是的是的,就是《科技乱炖》,我就说怎么这么巧

1 个赞

原来如此,原来还会有运营商的问题。涨知识了 :thinking:

主要还是防止浏览器缓存啦 owo

如果没有在header中显式声明cache-control: no-cache,浏览器总会尽可能使用cache,这样就会导致新传上去的静态资源不被浏览器更新,然后就炸了 owo

1 个赞

各级都有缓存哦

1 个赞

大家都想尽可能节省流量,但是版本更新就是不要它节省,那就只能这样了 owo

1 个赞

是这样的 本质就是击穿缓存

这都被你发现了?太强了

1 个赞