如何保证 HTTP 强制缓存的新鲜度 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lete
V2EX    Node.js

如何保证 HTTP 强制缓存的新鲜度

  •  2
     
  •   lete 2022-10-26 10:36:50 +08:00 6624 次点击
    这是一个创建于 1147 天前的主题,其中的信息可能已经有所发展或是发生改变。

    很多时候,我们的网站上都会对静态资源开启 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 条附言    2022-10-26 11:38:06 +08:00

    更详细的说明请看这篇文章: 《前端优化之静态资源缓存控制

    33 条回复    2023-02-11 16:08:48 +08:00
    1018ji
        1
    1018ji  
       2022-10-26 10:39:45 +08:00
    真是个好想法 大赞
    czgaotian
        2
    czgaotian  
       2022-10-26 10:45:48 +08:00
    前端打包出来的产物不是可以自带 hash 的吗
    这个包的应用场景是什么样的呢
    shyling
        3
    shyling  
       2022-10-26 10:49:28 +08:00
    一般不都是 index.html 一直刷新,引用的 js,css 跟着版本变 hash 吗?
        4
    lete  
    OP
       2022-10-26 10:56:15 +08:00
    @czgaotian 主要应用于再没有打包工具的情况下,比如一些项目的文档(当然有些文档生成框架是支持生成 hash 的),还有比如 hexo 、hugo 等这些打包出来的产物它们并没有生成 hash 的功能
    lete
        5
    lete  
    OP
       2022-10-26 10:58:01 +08:00
    @shyling 不太明白你的意思,一直刷新是没用的,除非你清理浏览器缓存或者强制刷新网页(ctrl+f5)
    shyling
        6
    shyling  
       2022-10-26 10:58:52 +08:00
    @shyling #3 我的意思是 index.html 不缓存
    killva4624
        7
    killva4624  
       2022-10-26 11:22:37 +08:00
    一般都直接用 cache-control 头来控制 index.html 就好了吧?
    lete
        8
    lete  
    OP
       2022-10-26 11:27:14 +08:00
    @shyling 可是你的其它资源比如 css 、js 、img 、mp3 、font 、等用了缓存,你的 index.html 用的依然是缓存啊
    lete
        9
    lete  
    OP
       2022-10-26 11:31:17 +08:00
    @killva4624 没错
    shyling
        10
    shyling  
       2022-10-26 14:41:11 +08:00
    @lete #8 是啊。。js 这些的路径自带 hash 呗
    qW7bo2FbzbC0
        11
    qW7bo2FbzbC0  
       2022-10-26 14:44:08 +08:00
    cdn 厂商不是帮忙做这些吗
    weizhen199
        12
    weizhen199  
       2022-10-26 14:46:41 +08:00
    我想起以前在 IIS 上写 silverlight 的时候,IE 的缓存策略非常的顽固,所以 HTTP HEAD 的那些 cache ,hint 都不识,我们发布的时候就给 app 名字后面加版本号,在一些配置文件后面.config?ramdon=xx
    lete
        13
    lete  
    OP
       2022-10-26 14:52:26 +08:00
    @shyling #10 怎么自带?手写?
    3dwelcome
        14
    3dwelcome  
       2022-10-26 14:56:26 +08:00
    关于这问题,我以前发过贴 https://v2ex.com/t/830203

    看来历史的轮子总是重复的。
    whistle24
        15
    whistle24  
       2022-10-26 14:57:47 +08:00
    @shyling 正解,现在用 webpack 等打包的基本都有配置打包后文件带 hash 值
    lete
        16
    lete  
    OP
       2022-10-26 15:08:55 +08:00
    @qW7bo2FbzbC0 cdn 有两种缓存
    1. 缓存原服务器的静态资源,规则由你选择,在缓存期间,任何请求都只会从 cdn 的网络中响应资源给用户(你服务器的任何资源修改 cdn 都不会去刷新(除非你手动在 cdn 里刷新),只有当缓存时间过了之后才会向你服务器获取),在此期间不会对你的服务器有任何连接
    2. 要么就是协商缓存,那么用户访问还是会去问服务器这个资源是不是最新的,要么就是强制缓存,这就是正常的强制缓存,无论服务器端怎么改变资源,浏览器都不会去访问服务器,只有过期了才会访问服务器
    lete
        17
    lete  
    OP
       2022-10-26 15:12:58 +08:00
    @whistle24 本文的 cache-hash 工具是给没有自带生成 hash 功能的场景使用,比如一些文档生成工具,它们只负责将 markdown 渲染出一个个文档页面,并没有生成 hash 的功能,当然有些文档生成工具也有自带的比如 vuepress
    whistle24
        18
    whistle24  
       2022-10-26 15:21:40 +08:00
    @lete 这样说的话,是可以理解的
    lete
        19
    lete  
    OP
       2022-10-26 15:30:43 +08:00
    @3dwelcome 看了一下,你列举的 3 个方法,第 1 个没看明白,但后两个方法存在问题,虽然都能解决你帖子的疑问

    第 2 种: 使用 etag 实际上是协商缓存,每次请求都会向服务器确认资源有没有变化,如果服务器线路比较拉跨,那么这个请求到服务器的时间也会随之变长,浏览器再等待服务器响应回来也需要时间,如果是强制缓存,就没有那么多的步骤,直接从浏览器本地缓存读取

    第 3 种: last-modifed-time ,它也是协商缓存,但区别在于 etag 判断的是标识(hash),last-modifed-time 判断的是最后修改时间,它同样需要把时间发送给服务器去判断
    yushiro
        20
    yushiro  
       2022-10-26 16:25:21 +08:00 via iPhone
    这个方案能解决 90%以上的情况,但我曾经遇到过,缓存机制不看参数,只看?之前的 url ,所以后来还是用文件名 hash 的方案。
    我遇到的情况并非在普通浏览器中,好像是微信的 webview 还是哪个手机 app 环境里面。
    3dwelcome
        21
    3dwelcome  
       2022-10-26 16:40:47 +08:00
    @lete 我原贴的意思是,如果浏览器直接读 html 里的 etag 或者 last-modifed-time ,就可以不协商,仅仅本地对比。

    现在浏览器没读,所以就只能发请求服务器进行协商。

    @yushiro 早期的手机浏览器设计很奇葩,会自作主张在 url 请求后面加?作为一些特殊标识。然后服务器收到两个?的参数,就会出问题了。
    lete
        22
    lete  
    OP
       2022-10-26 16:45:38 +08:00
    @3dwelcome 哦哦,是我没看明白,哈哈哈

    不过 w3c 没制定标准,浏览器厂商是不可能去做的,况且如果有浏览器厂商做了,其它厂商也不一定做
    lete
        23
    lete  
    OP
       2022-10-26 16:49:17 +08:00
    @yushiro 确实有些浏览器或套壳浏览器有这种问题
    liaohongxing
        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 跟着自动变 。感觉现在都用这种脚手架了吧
    CodingNaux
        25
    CodingNaux  
       2022-10-26 17:02:34 +08:00
    这种常见问题,应该都有方案
    iqoo
        26
    iqoo  
       2022-10-26 20:07:10 +08:00
    这方案十几年前就普遍使用了
    learningman
        27
    learningman  
       2022-10-27 01:35:48 +08:00
    有的 CDN ignore query string 的,你这白操作
    lete
        28
    lete  
    OP
       2022-10-27 09:15:27 +08:00
    @learningman 你可能理解错了,query string 主要是给浏览器辨别这个连接有没有缓存的,如果 url 变了就会像服务器索要新的资源,没变就直接充浏览器缓存中读取
    learningman
        29
    learningman  
       2022-10-27 09:20:01 +08:00
    @lete #28 你改 query string 刷了浏览器的缓存,但是 CDN 的缓存还是可能没刷啊。。。不如乖乖配 Cache Control
    lete
        30
    lete  
    OP
       2022-10-27 09:40:07 +08:00
    @learningman 不设置 CDN 的缓存不就可以了,直接 Cache-Control 设置强制缓存
    humbass
        31
    humbass  
       2022-11-05 00:00:48 +08:00
    我的天啊,真是这么玩的吗 ?如果是 HTML 的变化,一般前段打包器就已经做了这个工作,比如 webpack ,只要打包内部的索引( hash )就自动换了。

    难道我理解错了 楼主 的意思吗
    R1hu6Hs2sSN8pkVX
        32
    R1hu6Hs2sSN8pkVX  
       2023-02-07 17:55:44 +08:00
    这不就是协商缓存吗。。。
    lete
        33
    lete  
    OP
       2023-02-11 16:08:48 +08:00
    @whatFoxSay 不是协商缓存呀
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5159 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 08:05 PVG 16:05 LAX 00:05 JFK 03:05
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86