很多时候,我们的网站上都会对静态资源开启 HTTP 缓存,HTTP 缓存分为两种,但对于静态资源来说,我想,大部分人开的因该是强制缓存吧?
不过强制缓存有个缺点那就是没法保证资源的 新鲜度(最新的) ,只能等待缓存时间过期才能获取到最新的资源内容
于是我写了一个库 Cache-Hash 在线求 star✨ ,专门处理 HTTP 缓存破除的
我的博客已经用上了: https://blog.imlete.cn
通过给网站引入的资源,打上 hash 版本号,一旦内容改变,hash 会随着改变,这样即可通过改变 url 地址来破除缓存,能够保证网站所引用的资源是最新的
例如以下形式
<script src="https://demo.com/js/main.js?v=5e74b42bf5"></script>
可以通过使用 CLI (命令行工具) ,也可以使用 JavaScript API 来对静态资源的引用生成 hash
可以全局安装使用
npm install cache-hash -g
cache-hash --target source --output public
# 简写
cache-hash -t source -o public
如果你不想全局安装,可以使用 npx
npx cache-hash --target source --output public
它通过读取你给定的 target 目录,检测目录内的所有 html 、css 、js ,并对这些文件生成 AST(Abstract Syntax Tree) 即抽象语法树 ,之后通过修改 ast 语法树的内容后,再通过 ast 语法树编译回源代码即可
更详细的说明请看这篇文章: 《前端优化之静态资源缓存控制》
1
1018ji 2022-10-26 10:39:45 +08:00
真是个好想法 大赞
|
2
czgaotian 2022-10-26 10:45:48 +08:00
前端打包出来的产物不是可以自带 hash 的吗
这个包的应用场景是什么样的呢 |
3
shyling 2022-10-26 10:49:28 +08:00
一般不都是 index.html 一直刷新,引用的 js,css 跟着版本变 hash 吗?
|
4
lete OP @czgaotian 主要应用于再没有打包工具的情况下,比如一些项目的文档(当然有些文档生成框架是支持生成 hash 的),还有比如 hexo 、hugo 等这些打包出来的产物它们并没有生成 hash 的功能
|
7
killva4624 2022-10-26 11:22:37 +08:00
一般都直接用 cache-control 头来控制 index.html 就好了吧?
|
8
lete OP @shyling 可是你的其它资源比如 css 、js 、img 、mp3 、font 、等用了缓存,你的 index.html 用的依然是缓存啊
|
9
lete OP @killva4624 没错
|
11
qW7bo2FbzbC0 2022-10-26 14:44:08 +08:00
cdn 厂商不是帮忙做这些吗
|
12
weizhen199 2022-10-26 14:46:41 +08:00
我想起以前在 IIS 上写 silverlight 的时候,IE 的缓存策略非常的顽固,所以 HTTP HEAD 的那些 cache ,hint 都不识,我们发布的时候就给 app 名字后面加版本号,在一些配置文件后面.config?ramdon=xx
|
14
3dwelcome 2022-10-26 14:56:26 +08:00
|
16
lete OP @qW7bo2FbzbC0 cdn 有两种缓存
1. 缓存原服务器的静态资源,规则由你选择,在缓存期间,任何请求都只会从 cdn 的网络中响应资源给用户(你服务器的任何资源修改 cdn 都不会去刷新(除非你手动在 cdn 里刷新),只有当缓存时间过了之后才会向你服务器获取),在此期间不会对你的服务器有任何连接 2. 要么就是协商缓存,那么用户访问还是会去问服务器这个资源是不是最新的,要么就是强制缓存,这就是正常的强制缓存,无论服务器端怎么改变资源,浏览器都不会去访问服务器,只有过期了才会访问服务器 |
17
lete OP @whistle24 本文的 cache-hash 工具是给没有自带生成 hash 功能的场景使用,比如一些文档生成工具,它们只负责将 markdown 渲染出一个个文档页面,并没有生成 hash 的功能,当然有些文档生成工具也有自带的比如 vuepress
|
19
lete OP @3dwelcome 看了一下,你列举的 3 个方法,第 1 个没看明白,但后两个方法存在问题,虽然都能解决你帖子的疑问
第 2 种: 使用 etag 实际上是协商缓存,每次请求都会向服务器确认资源有没有变化,如果服务器线路比较拉跨,那么这个请求到服务器的时间也会随之变长,浏览器再等待服务器响应回来也需要时间,如果是强制缓存,就没有那么多的步骤,直接从浏览器本地缓存读取 第 3 种: last-modifed-time ,它也是协商缓存,但区别在于 etag 判断的是标识(hash),last-modifed-time 判断的是最后修改时间,它同样需要把时间发送给服务器去判断 |
20
yushiro 2022-10-26 16:25:21 +08:00 via iPhone
这个方案能解决 90%以上的情况,但我曾经遇到过,缓存机制不看参数,只看?之前的 url ,所以后来还是用文件名 hash 的方案。
我遇到的情况并非在普通浏览器中,好像是微信的 webview 还是哪个手机 app 环境里面。 |
21
3dwelcome 2022-10-26 16:40:47 +08:00
|
22
lete OP |
24
liaohongxing 2022-10-26 16:57:40 +08:00
vue-cli vite-cli nuxt-cli cra-cli nextjs-cli build 出来文件都自带 hash , 一般都是 index.html 设置 no-store 。index.html 里面引用的 js css images 跟着自动变 。感觉现在都用这种脚手架了吧
|
25
CodingNaux 2022-10-26 17:02:34 +08:00
这种常见问题,应该都有方案
|
26
iqoo 2022-10-26 20:07:10 +08:00
这方案十几年前就普遍使用了
|
27
learningman 2022-10-27 01:35:48 +08:00
有的 CDN ignore query string 的,你这白操作
|
28
lete OP @learningman 你可能理解错了,query string 主要是给浏览器辨别这个连接有没有缓存的,如果 url 变了就会像服务器索要新的资源,没变就直接充浏览器缓存中读取
|
29
learningman 2022-10-27 09:20:01 +08:00
@lete #28 你改 query string 刷了浏览器的缓存,但是 CDN 的缓存还是可能没刷啊。。。不如乖乖配 Cache Control
|
30
lete OP @learningman 不设置 CDN 的缓存不就可以了,直接 Cache-Control 设置强制缓存
|
31
humbass 2022-11-05 00:00:48 +08:00
我的天啊,真是这么玩的吗 ?如果是 HTML 的变化,一般前段打包器就已经做了这个工作,比如 webpack ,只要打包内部的索引( hash )就自动换了。
难道我理解错了 楼主 的意思吗 |
32
R1hu6Hs2sSN8pkVX 2023-02-07 17:55:44 +08:00
这不就是协商缓存吗。。。
|
33
lete OP @whatFoxSay 不是协商缓存呀
|