深入理解浏览器缓存机制 ( http )

一、介绍
http缓存:浏览器根据当前http请求报文策略网路资源存储到本地内存(memory cache)/硬盘(disk cache)中

缓存流程:

浏览器 浏览器缓存 服务端 发起请求,根据缓存规则验证缓存 没有缓存或者缓存标识失效/过期,发起网络请求 请求完成,返回请求结果,缓存标识 缓存网络资源,缓存标识 浏览器 浏览器缓存 服务端

二、访问缓存优先级

  • 次访问资源时,先从内存中查找,如果内存中有,直接加载
  • 如果内存中没有,则从硬盘中查找,如果硬盘中有,直接加载
  • 如果硬盘中也没有,就会进行网络请求,成功后将网络资源存储到内存/硬盘中

三、分类

  • 强缓存
  • 协商缓存

优先进行强缓存,强缓存失效后,进行协商缓存

强缓存

不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的Network选项中可以看到该请求返回200的状态码,并且Size显示from disk cache或from memory cache。强缓存可以通过设置两种 HTTP Header 实现:Expires 和 Cache-Control

Expires: Sun, 26 Apr 2020 18:00:00 GMT 最大过期时间 2020/04/26 18:00:00

Expires:缓存过期时间,如果请求资源在到期时间内,直接从缓存里读取。因为是绝对时间,受限于本地时间,如果修改本地时间,可能会导致缓存失效

Cache-Control:max-age=300

Cache-Control:max-age=300 代表当前请求返回时间的5分钟之后,再次请求,直接从缓存里读取。默认值 private:

Cache-Control 指令有很多,并且可以组合使用:

指令 作用
public 所有内容都将被缓存(客户端和代理服务器都可缓存)
private 所有内容只有客户端可以缓存
no-cache 不使用强缓存,使用协商缓存
no-store 所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
max-age 表示缓存将在多少秒后失效
s-maxage 同max-age作用一样,只在代理服务器中生效,s-maxage的优先级高于max-age

接下来我们测试一下强缓存:

注意:
深入理解浏览器缓存机制 ( http )_第1张图片

这里把勾去掉,否则不会使用缓存

serve.js

let express = require('express')
let app = express()
let fs = require('fs')
let router = express.Router() // 这里使用Router

// 设置全局响应头
router.all('*', (req, res, next) => {
  res.set({
    'Cache-Control':'max-age=300' // 5分钟缓存时间
  })
  next()
})

// 静态资源
router.use(express.static('dist')) // 里面有index.html / 图片等静态资源

router.get('/userList', (req, res) => {
  res.send({'name':'小明'})
})

app.use('/user',router) // 挂载

let server = app.listen(3000, '127.0.0.1', () => {
  let host = server.address().address
  let port = server.address().port

  console.log('Server running at http://' + host + ':' + port)
})

接下来我们访问 127.0.0.1:3000/user/index.html

可以看到 强缓存已生效
深入理解浏览器缓存机制 ( http )_第2张图片
接下来,我们F5刷新页面,此时进程还在,并且在缓存时间内,根据浏览器缓存原理,应该从 memory cache 中读取图片

注意:这里切勿 ctrl + F5 强制不走缓存
深入理解浏览器缓存机制 ( http )_第3张图片

我们可以看到 form memory cache 从内存中读取图片 !!!

接下来,我们把进程关掉,在缓存时间内,根据浏览器缓存原理,应该从 disk cache 硬盘中读取图片
深入理解浏览器缓存机制 ( http )_第4张图片
看到 form disk cache 从硬盘中读取图片,完全符合访问缓存优先级

接下来,我们尝试 5 分钟之后,也就是请求缓存时间到期后,再次请求
深入理解浏览器缓存机制 ( http )_第5张图片
我们可以看到,缓存时间到期后,直接从服务端发起请求

总结流程,在缓存时间内:

浏览器 内存 硬盘 服务端 发起请求,先在内存寻找 如果存在,内存直接返回 如果不存在,硬盘寻找 如果硬盘中存在缓存资源,硬盘直接返回 如果硬盘中不存在,则向服务端发起网络请求 请求完成,返回请求结果,浏览器缓存资源 浏览器 内存 硬盘 服务端

协商缓存

如果不设置 Cache-Control 默认public,max-age=0,当然我们可以设置为 Cache-Control : no-cache

serve.js

let express = require('express')
let app = express()
let fs = require('fs')
let router = express.Router() // 这里使用Router

// 设置全局响应头
router.all('*', (req, res, next) => {
  res.set({
    'Cache-Control':'no-cache' // 进行协商缓存
  })
  next()
})

// 静态资源
router.use(express.static('dist')) // 里面有index.html / 图片等静态资源

router.get('/userList', (req, res) => {
  res.send({'name':'小明'})
})

app.use('/user',router) // 挂载

let server = app.listen(3000, '127.0.0.1', () => {
  let host = server.address().address
  let port = server.address().port

  console.log('Server running at http://' + host + ':' + port)
})

接下来我们访问 127.0.0.1:3000/user/index.html

可以看到,Cache-Control : no-cache 已经生效
深入理解浏览器缓存机制 ( http )_第6张图片
我们发现返回值多了ETag 和 Last-Modified

Etag

代表我们当前请求的数据在服务端的唯一标识,首次请求时,服务端会返回Etag标识,浏览器下次请求时,会带上赋值后的 If-None-Match 参数,并且与返回的ETag进行对比,如果一致则命中协商缓存。返回 304 Not Modified

Last-Modified

代表请求的数据在服务端最后一次修改的时间,同理,首次请求时,服务端会返回Last-Modified标识,浏览器下次请求时,会带上赋值后的 If-Modified-Since 参数,并且与返回的Last-Modified进行对比,如果一致则命中协商缓存。返回 304 Not Modified

!!!注意:Etag 的优先级要高于 Last-Modified,所以请求时,如果ETag存在,则对比 If-None-Match,反之对比 If-Modified-Since

接下来我们测试协商缓存:
深入理解浏览器缓存机制 ( http )_第7张图片

可以看到,Etag 与 If-None-Match 对比一致,命中协商缓存,返回 304 Not Modified

然后,我们修改服务端静态资源,再次请求
深入理解浏览器缓存机制 ( http )_第8张图片
我们会看到浏览器保留的 If-None-Match 与 响应头 Etag 对比不一致,缓存策略失效!!!发送请求

总结协商缓存:

浏览器 内存 服务端 发起请求,如果有ETag 对比Etag / If-None-Match 若一致,返回缓存数据 304 如果不存在ETag,寻找Last-Modified,对比Last-Modified / If-Modified-Since,若一致,返回缓存数据 304 如果都不存在,则向服务端发送请求 请求完成,返回请求结果,浏览器缓存资源/标识 F5 与 ctrl+F5 都会释放内存 浏览器 内存 服务端

至此,我们就彻底搞懂http缓存机制

你可能感兴趣的:(前端技能,浏览器,缓存,http)