浏览器缓存机制详解

本文深入探讨了HTTP缓存机制,重点介绍了Expires、Cache-control策略及其属性,如Public、Private、no-cache、no-store、max-age、min-fresh、max-stale。同时,解释了Last-Modified和Etag的区别与使用场景,强调了它们在资源变动时间精确性和资源一致性的优势。此外,文章还阐述了用户操作对浏览器缓存的影响,以及缓存的处理流程和保质期的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

浏览器的缓存机制,主要指由 HTTP协议 定义的缓存机制。但也有非HTTP协议定义的缓存机制,如HTML Meta 标签,但所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。


下主要介绍HTTP协议定义的缓存机制

Expires策略(HTTP 1.0)

Cache-control策略

Cache-Control 用于指定缓存控制Cache-Control选择更多,设置更细致优先级高于Expires

Public —— 指示该响应可以被共享缓存缓存。
Private ——指示该响应只能作为私有缓存。

no-cache —— 指示请求或响应消息
no-store ——  在请求消息中发送将使得请求和响应消息都不使用缓存。
max-age —— 指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh —— 指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale —— 指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。


Last-Modified/If-Modified-Since

Last-Modified/If-Modified-Since要配合Cache-Control使用。

若资源改动过,则响应HTTP 200;若资源无修改,则响应HTTP 304 ,告知浏览器继续使用cache并更新缓存


Etag/If-None-Match

Etag/If-None-Match也要配合Cache-Control使用。

既生Last-Modified何生Etag

HTTP1.1Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

l  Last-Modified标注的最后修改只精确到秒级,如果某文件在1秒内,被修改多次,将不能准确标注文件的修改时间

l  如果某文件会被定期生成,但有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存

l  有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形

Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-ModifiedETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304

用户行为与缓存

浏览器缓存行为还有用户的行为有关!

用户操作

Expires/Cache-Control

Last-Modified/Etag

地址栏回车

有效

有效

页面链接跳转

有效

有效

新开窗口

有效

有效

前进、后退

有效

有效

F5刷新

无效

有效

Ctrl+F5刷新

无效

无效


缓存的处理流程

处理流程图,如上所示,下面分步骤具体介绍:

1)请求处理

用户发起一个HTTP请求,缓存获取到URL,根据URL查找是否有匹配的副本,这个副本可能在内存中,也可能在本地磁盘。

2) 新鲜度检测

如果缓存中存在所请求资源的副本,则进行新鲜度检测,检查这个副本有没有过期,如果没有过期,直接使用。如果已经过期,则进行再验证。

3)服务器再验证

缓存中的文档过期了并不代表他和服务器上的不一样,所以这个时候就需要问问服务器,过期的这段时间里这个文档到底有没有改变。如果改变了,缓存就会获取一份新的文档副本,然后发送给客户端。如果没有改变,缓存只需要获取新的首部,包括一个新的过期时间,并对缓存中的首部更新。

4)创建响应并返回

我们希望缓存看起来就像是来自原始服务器一样,缓存将已缓存的服务器响应首部作为响应首部,发送给客户端。


保质期的实现

HTTP中,通过 Cache-Control 首部和 Expires 首部为文档指定过期时间,通过对过期时间的判断,缓存就可以知道文档是不是在保质期内。Expires 首部和 Cache-Control:max-age 首部都是来告诉缓存文档有没有过期,为什么需要两个响应首部来做这件简单的事情了?其实这一切都是历史原因,Expires首部是HTTP 1.0中提出来的,因为他使用的是绝对日期,如果服务端和客户端时钟不同步的话(实际上这种情况非常常见),缓存可能就会认为文档已经过了保质期。

HTTP 1.1为了修正这个问题,引入了Cache-Control:max-age首部,这个首部使用相对时间来控制保质期,让一切变得更加合理。


服务器再验证

HTTP中,使用两个请求首部来完成这个功能:If-Modified-Sice 和 If-None-Match。为啥又要两个首部来完成这个功能了?答案还是因为历史的原因。一开始使用 If-Modified-Sice:<date>首部,date是上一次缓存文件时,响应中Last-Modified首部的值。

客户端拿着这个值,问服务器,这段时间内文件有没有修改过?服务器看了看这个文件的修改时间,如果没有修改过,会返回一个304 Not Modified的响应;如果修改过,把最新的文件返回给客户端。后来,人们发现这样有问题,因为就算修改时间变化了,文档也不一定发生改变!于是乎,就有了 If-None-Match:<tag>首部,tag是上一次缓存文档时,响应中Etag的值,Etag是一种唯一标识资源的方式。


试探性过期

如果响应中既没有Cache-Control:max-age首部又没有Expires首部,缓存可以计算出一个试探性最大使用期。这东西打个比方就是缓存会根据响应的Last-Modified来决定这文档靠不靠谱,需不需要再验证,如果Last-Modified中的日期是很早之前,那缓存就认为这文档挺靠谱,近期之内应该不会变化;如果Last-Modified中的日期是最近几天,那缓存可能就认为这文档可能经常改变,不靠谱。当然这么粗略的判断想想就知道不严谨,所以我们一定要设置Expires首部和Cache-Control首部。


写在最后

在chrome上为了保证文件安全,不信任缓存过期时间的设定,每次请求时都会询问服务器(再验证)。


原文地址:http://sojuker.blog.163.com/blog/static/13879087920121123113116655/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值