当前位置: 首页 > 工具软件 > xxl-cache > 使用案例 >

关于HTTP缓存Cache-Control

郭凯
2023-12-01

关于Cache-Control的特性

可缓存性

  • 代表http请求返回的内容所经过的任何路径中, 包括中间的http代理服务器, 以及发出请求的客户端浏览器
  • 都可以对返回内容进行缓存的操作,也就是把这份数据存在本地,下一次可以直接读取而非重新获取
  • 网络中有很多代理服务器和发起的客户端都可以进行缓存的操作,它的可缓存性就是指那些地方可以执行缓存操作
  • public:表示任何地方都可以进行缓存
  • private:表示发起请求的浏览器才可以进行缓存
  • no-cache:不表示不缓存,实际上,在每次请求中使用任何缓存响应之前,都要使用服务器重新验证。

到期

  • max-age=<seconds>
    • 表示设置缓存的到期时间,用秒表示
    • 过期后浏览器重新发起请求到服务器获取内容
  • s-maxage=<seconds>
    • s-maxage可代替max-age
    • 两个都设置了,在浏览器中用max-age,在代理服务器中用s-maxage
    • 该项只有在代理服务器里面才会生效
  • max-stale=<seconds>
    • 在max-age过期之后,如果返回的资源里存在max-stale设置
    • 即使max-age过期了,如果在max-stale时间内仍然可以使用过期的缓存,而不用去重新请求
    • max-stale在浏览器中用不到,浏览器在发起请求和静态资源请求中不会主动设置这个头
    • max-stale是发起请求的一方主动带的一个头,只有在发起端设置是有用的,在服务端返回中设置是没用的

重新验证

  • must-revalidate
    • 在设置的max-age缓存中已经过期了,必须去原服务端重新发起请求获取数据,来验证是否已经真的过期
    • 而不能直接使用本地缓存
  • proxy-revalidate
    • 用于缓存服务器中, 过期的时候必须去原服务器上请求最新内容,不能再使用本地缓存
  • 以上两个基本不会怎么用到

其他

  • no-store
    • 严格的本地和代理服务器都不可以存储缓存
    • 永远用的都是新的
  • no-transform
    • 用在代理服务器中,有些代理服务器会压缩和格式转换资源
    • 此设置告诉代理服务器不要改动资源

重要的原则

  • 以上头的设置都是原则性的,是一种规范,但是很多代理服务器可以完全不按着这个规范来做
  • Nginx做代理是可以配置缓存的,它的权重会更高

浏览器从本地读取缓存示例

  • test.html

    <script src="/script.js"></script>
    
  • server.js

    const http = require('http');
    const fs = require('fs');
    
    http.createServer((req, res) => {
        console.log('req come: ', req.url);
        if(req.url === '/') {
            const html = fs.readFileSync('test.html', 'utf8');
            // 默认是下面这个writeHead设置,不写也可以
            res.writeHead(200, {
                'Content-Type': 'text/html'
            });
            res.end(html);
        }
        if(req.url === '/script.js') {
            // 默认是下面这个writeHead设置,不写也可以
            res.writeHead(200, {
                'Content-Type': 'text/javascript'
            });
            res.end("alert('script loaded')");
        }
    }).listen(8000, () => {
        console.log('server is running on port 8000');
    });
    
  • 启动程序:$ node server.js

  • 访问:http://localhost:8000/

  • 弹出信息:script loaded

  • 检查浏览器Network, 查找script.js项

    • 显示 Status: 200 OK
    • Size: 199B transferred from network, resource size: 22B
    • Time: 3ms
  • 修改程序,针对script.js的访问设置Cache-Control如下所示

    res.writeHead(200, {
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=20' // 设置缓存时间为20s
    });
    
  • 重启服务:$ node server.js

  • 访问:http://localhost:8000/

  • 再次检查Network, Disable cache 保持未勾选状态

  • 刷新浏览器,检查浏览器Network, 查找script.js项

    • 显示 Status: 200 OK
    • Size: memory cache, Served from network, resource size: 22B
    • Time: 0ms
  • 可见第二次访问script.js时,浏览器从缓存中读取了,这就是Cache

  • 我们再次修改程序,针对script.js的返回,设置

    res.end("alert('script loaded!!!')");
    
  • 重启服务,$ node server.js

  • 再次访问:http://localhost:8000/

  • 弹出信息仍是:script loaded,没有新增的"!!!"

  • 经过20s后, 再次刷新页面

  • 弹出信息:script loaded!!!

  • 可见Cache-Control是客户端缓存, 与服务端无关

  • 服务端修改了js程序, 客户端访问的url仍是script.js, 没有发生变化

  • 因此,客户端仍在有效期内使用缓存资源

  • 这样,又会导致一个新的问题, 客户端无法及时的获取更细,如何解决呢?

    • 我们希望浏览器能缓存js,css,img等资源文件加快页面速度,同时,也希望浏览器能够及时更新最新的程序
    • 一般情况下,我们服务端设置的Cache-Control不需要变化, 可以设置一个较长时间的max-age
    • 常见的前端解决方式是在构建流程时,会根据js内容的变化进行哈希计算,在打包后的js文件名上添加一串最新的哈希码
    • 如果内容不变,哈希码不变,反应在web页面上就是请求js的资源地址也就不变,就不会请求最新的文件,仍使用客户端缓存文件
    • 如果内容变化,哈希码变化,请求js的资源的路径发生变化,此时就会自动请求最新的资源,不会再使用缓存资源
  • 另外,关于Cache-Control的设置,还可以在后面添加更多内容

    • 如:'Cache-Control': 'max-age=20, public'
    • 不同的值会产生不同的效果, 用逗号分开即可
  • 在代理服务器上,Nginx也可以配置一些代理的Cache-Control的头,此处不再赘述

 类似资料: