前端性能优化必修课:HTTP缓存机制详解

前端性能优化必修课:HTTP缓存机制详解

缓存的原理:为什么我们需要它?

想象一下,你是一个勤劳的外卖小哥。如果每次顾客点同一款菜,你都要跑回餐厅取,那得多累啊!所以聪明的你决定:第一次送餐时,顺便带一份备用的放在顾客家门口的保温箱里。下次顾客再点同样的菜,你先看看保温箱里的还新鲜不?新鲜就直接给他,省得再跑一趟餐厅。

这就是HTTP缓存的核心原理:在首次请求后保存一份资源的响应副本,当用户再次发起相同请求时,如果判断缓存命中则拦截请求,直接返回之前存储的响应副本,从而避免重新向服务器发起资源请求。这就像是网络世界的"能源守恒法则"——能不跑的路,就别跑!

缓存的技术种类:冰箱有大有小

缓存技术多种多样:代理缓存、浏览器缓存、网关缓存、负载均衡器及内容分发网络等,但归根结底可分为两大类:共享缓存和私有缓存。

  • 共享缓存:就像公司茶水间的公共冰箱,缓存内容可被多个用户共享使用,如公司内部架设的Web代理服务器;

  • 私有缓存:相当于你家里的专属冰箱,只能由单个用户使用的缓存,如浏览器缓存。

而HTTP缓存按照验证机制又可细分为两种模式:

  • 强制缓存:不用询问服务器,直接使用缓存(就像你相信冰箱里的牛奶没过期,直接喝)
  • 协商缓存:获取缓存资源前先询问服务器缓存是否过期,过期则重新请求资源,未过期则使用缓存内容(就像你不确定牛奶是否新鲜,先问问室友)

强制缓存:我说了算

强制缓存相关字段:两位指挥官

与强制缓存相关的两个关键字段:Expires(老将军)和Cache-Control(新统帅)。

Expires的强制缓存应用:老式的约定

Expires:响应头包含一个明确的日期/时间,表示在此时间之后,响应过期。
在Cache-Control响应头设置了"max-age"或者"s-max-age"指令时,这位老将军Expires会被完全忽略。

http.createServer((req,res) => {
   
 res.writeHead(200, {
   
   Expires: new Date('2022-1-1 12:00:00').toUTCString()
 })
})

前端性能优化必修课:HTTP缓存机制详解_第1张图片

Expires的致命缺陷:它依赖客户端的时间戳,就像你和朋友约定下午3点见,但你们的手表时间不一致,导致约会失败。同样,当客户端时间和服务器时间不一致时,缓存判断会出错。这就是为什么我们需要一个更可靠的指挥官。

Cache-Control:现代化的缓存指挥官

Cache-Control:这是一个通用消息头字段,被用于HTTP请求和响应中,通过指定各种指令来精确控制缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定会被包含在响应中。

Cache-Control的强制缓存应用:精确的时间控制

设置缓存过期时间,5秒之内缓存有效,超过5秒需要重新请求资源。就像告诉你的同事:“这杯咖啡放5秒内喝完,否则我就倒掉重泡!”

http.createServer((req,res) => {
   
 res.writeHead(200, {
   
   'Cache-Control': 'max-age=5'
 })
})

前端性能优化必修课:HTTP缓存机制详解_第2张图片

Cache-Control的其他参数:缓存的指挥棒

no-cache:强制使用协商缓存,每次都需要和服务器确认缓存是否有效。

客户端可以缓存资源,但每次使用缓存资源前都必须重新验证其有效性。每次都会发起HTTP请求,当缓存内容有效时跳过HTTP响应体的下载。就像每次吃剩菜前都要先闻一闻是否变质——谨慎使用,但不浪费。

no-store禁止使用任何缓存。相当于"这份机密文件看完就销毁,不准保存副本!"—适用于敏感数据或经常变化的内容。

private:响应资源不可以被代理服务器缓存。就像你的私密日记,只能放在自己抽屉里,不能放在公共书架上——适用于用户个人信息。

public:响应资源可以被浏览器代理服务器缓存。就像公开的参考书,可以放在图书馆供所有人查阅——最大化缓存效益。

一般不容易变动的资源可以设置public属性。例如:图像、CSS文件和JS文件等静态资源。

max-age:设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间。就像食品的保质期,不是具体日期,而是"自购买之日起30天内食用"—更加灵活可靠。

s-maxage:当设置public属性时生效,表示代理服务器缓存失效时间。就像图书馆的借阅期限,只对公共图书有效——专门针对CDN等共享缓存设计。

前端性能优化必修课:HTTP缓存机制详解_第3张图片

Cache-Control能作为Expires的完全替代方案,并且拥有其所不具备的一些精细缓存控制特性。在现代项目实践中使用它就足够了,目前Expires还存在的唯一理由是考虑可用性方面的向下兼容。就像智能手机已经可以完全替代传统电话,但有些老年人还是习惯用按键式电话——技术演进中的过渡期现象。

Pragma:古老的缓存控制器

Pragma值有no-cache与no-store,优先级大于Cache-Control,即:

pragma -> cache-control -> expires

这就像公司里的命令链:CEO的命令 > 部门经理的命令 > 组长的命令。在现代开发中,除非需要兼容HTTP/1.0的古老客户端,否则很少单独使用它。

协商缓存:当浏览器和服务器开始讨价还价

协商缓存原理:先问一问再决定

协商缓存:使用本地缓存前,向服务器发起GET请求,与服务器协商当前本地缓存是否过期。就像使用冰箱里的食材前,先问问室友:“这个还能吃吗?”—既保证了内容的新鲜,又避免了不必要的资源传输。

主要通过Last-Modified和ETag两种机制来实现精确判断。

基于Last-Modified的协商缓存:时间戳比对法

设置Last-Modified字段为缓存内容最后修改时间,相当于给资源贴上"最后编辑于XX时间"标签。

客户端再次请求该资源时会自动携带If-Modified-Since字段,该字段值为上次请求时服务器返回的Last-Modified值。

服务端会比对这两个字段值:

  • 如果两者一致,说明资源未被修改,返回304状态码告知客户端可以继续使用缓存
  • 如果两者不一致,说明资源已更新,返回200状态码和最新的资源内容

请求流程图:一次完整的协商过程

你可能感兴趣的:(前端架构,计算机基础,前端,性能优化,http,缓存,网络协议,javascript,node.js)