V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lete
V2EX  ›  Node.js

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

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

    很多时候,我们的网站上都会对静态资源开启 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 吗?
    lete
        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 )就自动换了。

    难道我理解错了 楼主 的意思吗
    whatFoxSay
        32
    whatFoxSay  
       2023-02-07 17:55:44 +08:00
    这不就是协商缓存吗。。。
    lete
        33
    lete  
    OP
       2023-02-11 16:08:48 +08:00
    @whatFoxSay 不是协商缓存呀
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5768 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 03:35 · PVG 11:35 · LAX 20:35 · JFK 23:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.