浏览器缓存机制

私人博客

许小墨のBlog —— 菜鸡博客直通车

系列文章完整版,配图更多,CSDN博文图片需要手动上传,因此文章配图较少,看不懂的可以去菜鸡博客参考一下配图!

系列文章目录

前端系列文章——传送门
后端系列文章——传送门



浏览器缓存机制

缓存机制有很多,例如:浏览器缓存机制、服务器缓存机制、代理服务器缓存。。。

我们在这里主要说浏览器的缓存机制。

浏览器的缓存机制分为两种:

  • 强制缓存
  • 协商缓存

浏览器缓存机制主要是由响应头控制的。

强制缓存

通常浏览器的请求中包含disk cache或memory cache就表示有强制缓存了。

强制缓存只要服务器设置响应头就行,客户端不需要配合。

设置强制缓存的响应头包含:

  • expires
  • pragma
  • cache-control

expires和pragma是在http1.1之前就已经存在的两个键。

cache-control是http1.1之后才有键,所以优先级比expires要高。

expires

expires主要用于设置缓存的时间,值是RFC 2822 格式的时间字符串,如果设置的值不是这样一个字符串或不是一个时间,则设置了也不会生效。

例:

// 获取RFC 2822格式的时间格式字符串
function getRFC2822Date(addSeconds = 3) {
  const RFC2822Format = "ddd, DD MMM YYYY HH:mm:ss [GMT]";
  return moment()
    .utc()
    .add(addSeconds, 's')
    .format(RFC2822Format)  
}

console.log(getRFC2822Date());

app.get('/expires', (req, res) => {
    console.log('请求来了')
    // 浏览器默认会有etag缓存,所以需要先取消
    app.set('etag', false)
    // 设置expires缓存,有效期为3s
    res.setHeader(
        'Expires',
        getRFC2822Date()
    )
    res.send(`
        <script>
        	function getData() { fetch('http://localhost:3000/expires')}
        </script>
        <div>
            Expires!
            <button οnclick="getData()">re get</button>
        </div>`
    )
})

pragma

对应的值只有no-cache,是用来防止缓存的,只要设置了这个响应头就不会被缓存。

例:

function getRFC2822Date(addSeconds = 10) {
  const RFC2822Format = "ddd, DD MMM YYYY HH:mm:ss [GMT]";
  return moment()
    .utc()
    .add(addSeconds, 's')
    .format(RFC2822Format)  
}

app.get('/pragma', (req, res) => {
    app.set('etag', false)
    res.setHeader(
        'Expires',
        getRFC2822Date()
    )
    res.setHeader('Pragma', 'no-cache')
  	res.send(`
      	<script>
      		function getData() { fetch('http://localhost:8800/pragma')}
      	</script>
      	<div>
      		Pragma!
      		<button οnclick="getData()">re get</button>
      	</div>`
     )
})

虽然设置了expires,但也不会被缓存,因为设置了Pragma,取消缓存了。

cache-control

跟expires也是用于设置缓存的,对应的值有很多,但我们通常使用的只有一个max-age,用于设置缓存有效期,单位秒。

  • private:内容是对用户私有的,只能在浏览器端缓存,不能在其他地方(缓存除了浏览器可以缓存,还可以有代理服务器的缓存)缓存
  • public:内容是公开的,可以在任何地方进行缓存,可以是浏览器,也可以是代理服务器
  • no-store:内容不可以被任何地方缓存
  • no-cache:表示内容可以被缓存,但是浏览器每次都需要请求服务器,对内容进行对比校验
  • max-age:缓存内容的过期时间,单位是秒,使用起来比exprires更加友好。
  • s-max-age:作用是一样的,但是这个值通常代表代理服务器上的时间,如果浏览器中同时有这两个属性, 浏览器有限使用max-age
  • must-revalidate:在某些情况下,服务器无法访问,浏览器会使用缓存的内容,哪怕这个缓存的有效期已经超过了max-age,超过后必须去请求服务器。
  • proxy-revalidate:作用跟muse-revalidate一样。针对代理服务器。

例:

app.get('/cacheControl', (req, res) => {
  console.log('请求来了');
  // 有效期3s
  res.set('cache-control', 'max-age=3')
  res.send(`
    <script>
        function getData() { fetch('http://localhost:3000/cacheControl')}
    </script>
    <div>
        Cache-Control max-age!
        <button οnclick="getData()">re get</button>
    </div>`
    )
})

协商缓存

协商缓存是服务器设置缓存,但是需要客户端配合,不过配合是自动配合,也不需要手动去设置。

Last-Modified

服务器设置协商缓存的响应头是Last-Modified,值是一个时间戳。

具体过程:当服务器没有设置Last-Modified的时候,客户端也不会有If-Modified-Since;如果第一次请求服务器设置了Last-Modified响应头,第二次请求的时候,客户端会自动带上If-Modified-Since请求头,值是第一次服务器响应的Last-Modified的值。服务器接收到第二次请求的时候,先获取到If-Modified-Since的值,跟自己设置的Last-Modified的值进行对比,如果相等,说明,内容不需要进行更改,响应304状态码;如果不相等,说明内容需要更新,响应新内容。

例:

准备好被静态托管的静态资源:

<body>
<button>按钮</button>
</body>
<script>
document.querySelector('button').onclick = function() {
    var xhr = new XMLHttpRequest;
    xhr.open('get','/lastModify');
    xhr.send()
    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
            if(xhr.status>=200 && xhr.status<300){
                var res = xhr.responseText;
                console.log(res);
            }
        }
    }
}
</script>

创建服务器,进行静态资源托管:

const express = require('express')
const app = express()
app.listen(3000)
app.use(express.static('public'))

处理点击后发起的请求,并处理协商缓存:

app.get('/lastModify', (req, res) => {
    // 取消强制缓存
    res.set('cache-control', 'no-cache')
    let mtime = fs.statSync('./data.json').mtime
    res.setHeader('Last-Modified', mtime.toGMTString())
    if(req.headers['if-modified-since'] && req.headers['if-modified-since'] === mtime) {
        res.status(304)
    } else {
        res.send(fs.readFileSync('./data.json'))
    }
})

被读取的data.json文件:

{
    "name": "张三"
}

第一次请求响应状态码是200,后续不许改data.json文件,响应状态码为304,直到修改data.json后响应状态码再变成200。

ETag

ETag也是服务器开启的协商缓存,优先级比Last-Modified高。

服务器只要开启了ETag,会在响应头中携带ETag响应头,下次请求的时候,客户端会自动携带If-None-Match请求头,服务器会自动对比是否一致,一致就返回304,不一致,就重新响应新内容,并响应200。

原理跟if-modified-since一样,只是自动了。

准备好被静态托管的静态资源:

<body>
<button>按钮</button>
</body>
<script>
document.querySelector('button').onclick = function() {
    var xhr = new XMLHttpRequest;
    xhr.open('get','/etag');
    xhr.send()
    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
            if(xhr.status>=200 && xhr.status<300){
                var res = xhr.responseText;
                console.log(res);
            }
        }
    }
}
</script>

创建服务器,进行静态资源托管:

const express = require('express')
const app = express()
app.listen(3000)
app.use(express.static('public'))

处理点击后发起的请求,并处理协商缓存:

app.get('/etag', (req, res) => {
    app.set('etag', true)
    res.send('etag')
})

内容不变则一直是304,内容变了重新响应200。

总结

通常会将html设置为协商缓存,其他静态资源设置为强缓存。

f5刷新会暂时禁止强缓存,还会有协商缓存,ctrl+f5会禁止所有缓存策略。


本博文缺失大量图片,严重影响内容完整性以及阅读体验,完整内容请前往本人菜鸡博客——许小墨のBlog

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

许小墨~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值