HTTP 缓存及其工作方式

受众是更新不频繁的静态资源
为什么要使用HTTP缓存?
减少服务器负载压力,每次请求完可能要渲染页面,用户体验不好
缓存之后,第一次打开稍慢,后面进来很快

缓存的内容?
缓存的更多是一些静态资源文件。如js,图片等更新频率不大的静态资源
不是缓存某一个响应,而是静态资源文件
因此发现第一次进网页慢,后面进来就快了

Expires

响应头,HTTP1.0的属性,代表资源过期时间,由服务器返回提供,在与HTTP1.1的cache-control:max-age共存的情况下,优先级要低

Cache-Contro

请求/响应头,缓存控制字段
no-store:所有内容都不缓存
no-cache:缓存,但是浏览器使用缓存前,会请求服务求判断缓存资源是否是最新(只用不过期的缓存)
max-age=x(单位秒):请求缓存后的X秒不再发起请求(缓存后的多少秒内不发起缓存,http1.1的属性,和1.0的expires类似,但是优先级要高)。
s-maxage=x(单位秒):代理服务器请求资源缓存后的x秒不再发起请求,只对CDN缓存有效
public:客户端和代理服务器(CDN)都可缓存
private:只有客户端可以缓存Expires

Cache-Control:max-age 和 Expires的区别

Expires和max-age的区别:
Expires和max-age都可以用来指定文档的过期时间,但是二者有一些细微差别bai

1.Expires在HTTP/1.0中已经定义,Cache-Control:max-age在HTTP/1.1中才有定义,为了向下兼容,仅使用max-age不够;

2.Expires指定一个绝对的过期时间(GMT格式),这么做会导致至少2个问题

  1. 客户端和服务器时间不同步导致Expires的配置出现问题
    2)很容易在配置后忘记具体的过期时间,导致过期来临出现浪涌现象;

3.max-age 指定的是从文档被访问后的存活时间,这个时间是个相对值(比如:3600s),相对的是文档第一次被请求时服务器记录的Request_time(请求时间)

4.Expires指定的时间可以是相对文件的最后访问时间(Atime)或者修改时间(MTime),而max-age相对对的是文档的请求时间(Atime)

5.在Apache中,max-age是根据Expires的时间来计算出来的max-age = expires- request_time:(mod_expires.c)
429 expires = base additional;
430 apr_table_mergen(t, "Cache-Control",
431 apr_psprintf(r->pool, "max-age=%" APR_TIME_T_FMT,
432 apr_time_sec(expires - r->request_time)));
注:如果是A,base=request_time,M的话base=finfo.mtime.
expires - request_time得到max-age,如果Expires根据的是A(也就是AccessTime)设置的(A后面的值就是addtional),那么expires设置的值就等于addtional值,但是如果Expires根据的是Mtime,那么如果M后面的参数小于最后修改时间到当前时间的差(比方说2小时前修改了文件(19:00:00),现在设置M3600(现在是21:00:00)并且访问,max-age=expires-request_time = (finfo.mtime additional)- request_time),计算出的max-age就是负数(可以试验看到这个结果):
max-age = (19:00:00 3600/3600) - 21:00:00 = -3600s
这样,在Apache中,max-age就不仅仅是相对Atime的时间了,如果设置为M,相对的是Mtime。

HTTP1.1 If-Modified-Since Last-Modified

If-Modified-Since
请求头,资源最新修改时间,由浏览器告诉服务器。(其实就是上次服务器给的Last-Modified)
和last-modified是一对,它两会进行对比,共同决定资源要不要重新发送。

Last-Modified
响应头,资源最新修改时间,由服务器告诉浏览器
和if-Modified-Since是一对,它两会进行对比,共同决定资源要不要重新发送。

HTTP1.1 If-None-Match Etag

If-None-Match
请求头,缓存资源标识,由浏览器告诉有服务器(其实就是上次服务器给的Etag)
和Etag是一对,它两会进行对比

Etag
响应头,资源标识,由服务器告诉浏览器的资源标识
和if-None-Match是一对

HTTP缓存工作方式

场景一:让服务器与浏览器约定一个文件过期时间Expires
服务器设置了Expires和f.js
浏览器对比当前时间,判断是否大于Expires(是否超过了约定的过期时间)
如果时间过期了,就再次发起请求加载最新资源

如果约定时间之后资源依然没有修改呢?看场景二

场景二:让服务器与浏览器约定文件过期时间的基础上,再加一个文件最新修改时间(last-modified)的对比
last-Modified与if-Modified-Since。

  1. 如果当前时间没有超过过期时间expires,那么就使用本地缓存资源
  2. 如果超过了当前时间,但是浏览器的文件修改时间if-modified-since与服务器的last-modified时间没有差异,即不存在文件修改,那么依然使用本次缓存。注意是由服务器拿到请求中的if-modified-since和last-modified对比
  3. 在2的基础上,如果if-modified-since与last-modified有差异,说明文件有更改,那么就不再使用缓存而是加载最新资源

具体过程如下图:
请求头的Cache字段里面加上if-since-modified
响应头的entity字段里面会有last-modified
https://img2020.cnblogs.com/blog/1471668/202012/1471668-20201229220015149-1325137555.png)

到了过期时间,再对比文件修改时间
如果到期了,文件也修改了,那么返回新的
(在请求头加上if-Modified-since,其实就是服务器返回的last-Modified。如果相等就返回304 not Modified,你还是访问本地缓存吧)

问题: 极端情况,last-Modified精确到秒(GMT格式),可能在一秒以内改变了资源,收不到更新,看场景三
让服务器与浏览器再过期时间expires+last-Modified的基础上,增加一个文件内容唯一对比标记--ETag与If-None-Match
仅仅使用Expires不稳定(服务器指定的是一个绝对的过期时间,如果客户端和服务器时间不同步那么会出现问题,另外很容易在配置后忘记具体过期时间,导致过期来临出现对某个资源的请求峰值(专业一点叫浪涌现象),另外存在ATime和MTime),加入一个max-age来代替,再接入一个唯一标识ETag(具体是一个hash值,可详查)对比标记和if-None-Match

f.js+Expires过期时间+max-age过期时间+last-Modified(文件最后修改时间)+Etag文件内容标识

因此流程变为:

  1. expires+max-age(max-age优先级高,同时设置的话expires就没用了):判断过期时间,如果没过期不加载最新资源
  2. if-Modified-since + last-modified+: 如果过期了,再对比文件最后修改时间,如果有变化就加载最新资源,否则使用缓存
  3. if-None-Match + eTag:如果没过期,考虑到2过程的时间是GMT格式,精确到秒,存在一秒以内资源更新的极端情况,那么再对比文件唯一标识Etag(hash值),如果文件不唯一,那么加载最新资源

请求头的cache字段有
Cache-Control:max-age=60
if-modified-since:GMT时间
if-none-match:hash

响应头的entity字段有
ETag
Last-Modified:GMT时间

eTag优先级比if-None-Match高,毕竟是解决1秒内更新的问题

以上方案都有缺陷,如果max-age,或者expires不过期,浏览器无法主动感知服务器的文件变化

缓存改进方案

上述:
修改时间对比,唯一标识对比,建立在两者文件路径相同的情况下
如果是f-hash1.js f-hash2.js
如果是两个不同的文件(前提),那么根本不存在文件对比的时间
因此只需要在项目发布的时候,添加md5就行了

1.md5/hash缓存
通过不缓存html,为静态文件添加MD5或者hash标识,解决浏览器无法跳过缓存过期时间主动感知文件变化的问题(说起来上述的方案是递进关系,时间没过期也不会进入Etag等流程?)

2.CDN
s-max-age
什么是CDN?
CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,是用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

优点是:

  1. 通过分流的形式,降低了源站的负载压力
  2. 解决了跨地区访问的方式,联通和电信

CDN缓存的工作方式

第一次请求,cdn和浏览器都进行请求
后续请求

  1. 对比缓存时间
  2. 缓存没过期,返回304
  3. 缓存过期,向服务器拿到最新资源,返回给浏览器

缓存本身针对于更新频率不高的静态文件

浏览器操作对缓存的影响

  1. Expires/Cache-Control
  2. Last-Modified/Etag
    地址栏回车、页面连接跳转、新开窗口时 1和2都有效
    F5刷新 1失效,2有效
    ctrl+F5刷新(强制请求) 1和2都失效
posted @ 2022-05-26 18:51  IslandZzzz  阅读(68)  评论(0编辑  收藏  举报