http缓存详解

Table of Contents

前言

http缓存主要针对如css,js,图片等更新频率不大的静态文件。

http缓存字段的描述

根据请求和响应分为:

Request Headers(浏览器端)

if-modified-since
请求头,缓存最新修改的时间,浏览器询问服务器,服务器会将它与last-modified进行比对
if-none-match
请求头,缓存标识,浏览器询问服务器询,服务器会将它与etag进行比对

Response Headers(服务器端)

cache-control
控制http缓存的最高指令
常用值有:
1. no-store: 所有内容都不缓存
2. no-cache: 缓存,但是浏览器使用缓存前,都会请求服务器判断缓存是否是最新,过期的缓存就不使用
3. max-age=x(单位秒)在缓存后的x秒内不发请求,是http1.1的属性,类似于expires,但优先级高于expires
4. s-maxage=x(单位秒)代理服务器请求源站在缓存后的x秒内不发请求,只对CDN有效
5. public 客户端和代理服务器(CDN)都可缓存
6. private 只有客户端可以缓存

last-modified
响应头,缓存最新修改的时间,服务器返回给浏览器,优先级小于etag

etag
响应头,缓存标识,服务器返回给浏览器,优先级高于last-modified

expires
响应头,代表缓存过期时间,服务器返回,是http1.0的属性,优先级小于max-age

使用http缓存的原因

  1. 客户端每次都要请求服务器,浪费流量;
  2. 服务器每次都得提供查找,下载,请求用户基础如果较大,服务器存在较大压力;
  3. 客户端每次请求完都要进行页面渲染,用户体验较差。

http缓存字段的关系

服务器和浏览器的对话

我将从服务器和浏览器的日常对话来阐述各个字段的起因和来由。
为了简化,服务器称为S,浏览器称为C
第一次对话(expires的由来)

C: S,S,我要一个a.css文件,快发给我!!!
S: 烦死了,给你,在expires时间前别来烦我!!!

第二次对话(last-modified和if-modified-since的由来)

C: S, S, 我的a.css文件到期了,你快给我发一个新的!!!
S: 新的a.css? 它有修改过吗? 你之前用的就是最新的吧? ... 
   呃😓我也不知道了,要不我们都记录一下时间吧?
   我用last-modified记录a.css的最后修改时间,
   至于你就用if-modified-since吧?
   如果没有修改过,我就返回给你304状态码
C: 好吧...

……
中间过了,若干年,发生了很多事,比如http1.0升级到了http1.1
……

第n次对话(max-age的由来)

C: S, S, 我要一个文件a.css,我的expires已经过期了,
   你看一下这个文件修改了吗?修改了就发给我,好吗?
S: C啊, 你好low啊, 👎怎么还在用expires啊?毕竟你们那个客户端也是有钱的,
   你们不是已经支持http1.1协议了吗?你该与时俱进,使用max-age啊,
   你看这个比expires可靠多了啊?
C: 哦😯... 我知道了, 我以后优先使用max-age

第n+1对话(etag和if-none-match的由来)

C: S, S, 你知道吗?出了新的判断文件是否修改的方法叫做if-none-match。
S: 当然了,我这边叫做etag, 我们以后优先使用这个这个交流吧?
C: 恩恩,好的

问题总结

虽然浏览器和服务器可以精确的比较缓存文件的差异,但在max-age或expires时间内,浏览器无法感知服务器文件的变化。

http缓存解决方案

md5/hash缓存

为了解决上面在max-age和expires期间无法感知服务器文件变化的问题,下面提出的解决方案:

上面那个问题的前提就是服务器和浏览器两者文件的标识完全相同,比如路径相同。
因此我们只需要每次在服务器上发布项目的时候给修改的文件添加不同的md5和hash标识就可以了。
目前现成的解决方案就有webpack提供的webpack-md5-hash插件。

CDN缓存

CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。
简而言之,CDN理解成浏览器与服务器之间的临时站点,它会替服务器处理一部分的浏览器请求,从而整理减轻总服务器的压力。

参考链接