admin管理员组

文章数量:1531282

浏览器缓存

浏览器缓存可以有效释放服务器的压力,还可以提高用户体验,提高Web应用的性能。

浏览器缓存分为强制缓存和协商缓存。

一般这两种都是一起使用的。

强制缓存

强制缓存的含义是,当客户端请求后,会先访问缓存数据库看缓存是否存在。如果存在则直接返回;不存在则请求真的服务器,响应后再写入缓存数据库。

可以造成强制缓存的字段是 Cache-controlExpires

Expires

这是 HTTP 1.0 的字段,表示缓存到期时间,是一个绝对的时间 (当前时间+缓存时间),如:

Expires: Thu, 10 Nov 2017 08:45:11 GMT

但是,这个字段设置时有两个缺点:

  • 由于是绝对时间,用户可能会将客户端本地的时间进行修改,而导致浏览器判断缓存失效,重新请求该资源。此外,即使不考虑自行修改的因素,时差或者误差等因素也可能造成客户端与服务端的时间不一致,致使缓存失效。

  • 写法太复杂了。表示时间的字符串多个空格,少个字母,都会导致变为非法属性从而设置失效。

Cache-control

已知 Expires 的缺点之后,在 HTTP/1.1 中,增加了一个字段 Cache-control,该字段表示资源缓存的最大有效时间,在该时间内,客户端不需要向服务器发送请求

这两者的区别就是前者是绝对时间,而后者是相对时间。如下:

Cache-control: max-age=2592000

下面列举一些 Cache-control 字段常用的值:(完整的列表可以查看 MDN)

  • max-age:即最大有效时间,在上面的例子中我们可以看到

  • must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效。

  • no-cache:虽然字面意思是“不要缓存”,但实际上还是要求客户端缓存内容的,只是是否使用这个内容由后续的协商缓存来决定。

  • no-store:真正意义上的“不要缓存”。所有内容都不走缓存,包括强制缓存和协商缓存。

  • public:所有的内容都可以被缓存(包括客户端和代理服务器, 如 CDN

  • private:所有的内容只有客户端才可以缓存,代理服务器不能缓存。默认值。

Cache-control 是一个相对时间,即使客户端时间发生改变,相对时间也不会随之改变,这样可以保持服务器和客户端的时间一致性。而且 Cache-control 的可配置性比较强大。Cache-control 的优先级高于 Expires

当命中缓存并且缓存未过期时,不会向服务器发送请求,直接使用缓存的资源,这叫做强制缓存。可以有效减少浏览器发送网络请求的次数,有效减缓服务器的压力。

协商缓存

协商缓存是当服务器的缓存过期了,那么就会向服务器发送网络请求,并且会携带在请求头携带一些请求字段,向服务器询问是否可以继续使用缓存的资源,如果服务器校验后,缓存没有过期,将会返回304,并且不会响应资源,而是要求浏览器直接使用缓存的资源并且更新缓存的过期信息。

与协商缓存相关的字段有两组

Last-Modified(响应头) & If-Modified-Since(请求头)

Etag(响应头) & If-None-Match(请求头)


浏览器请求资源,响应头会携带Last-Modified,记录资源上次更新的一个时间。

当浏览器命中缓存但强制缓存失效,也就是资源过期了,那么就会发送请求,请求该资源,并且在请求头中携带If-Modified-Since字段,该字段记录了Last-Modified(资源上次更新的一个时间),服务器拿到后会进行校验,如果资源没有过期,那么就返回304以及最新的缓存指令,要求浏览器使用缓存并且更新缓存的信息,该响应不会响应资源。

但是他还是有一定缺陷的:

  • 如果资源更新的速度是秒以下单位,那么该缓存是不能被使用的,因为它的时间单位最低是秒。

  • 如果文件是通过服务器动态生成的,那么该方法的更新时间永远是生成的时间,尽管文件可能没有变化,所以起不到缓存的作用。

为了解决上述问题,出现了一组新的字段 EtagIf-None-Match

Etag 可以认为是文件的一个特殊标识hash(只要资源没有发生改变,etag不会发生改变),请求过程如上,服务器响应etg字段,浏览器命中缓存但缓存过期,发送携带 If-None-Match(资源的唯一标识)字段的请求,浏览器进行比对后,资源没有更新则响应304以及最新的缓存指令,要求浏览器使用缓存并且更新缓存的信息,该响应不会响应资源。

如果资源在服务器更新了,那么服务器跟第一次发送网络请求没有什么区别,正常响应并且携带缓存指令要求浏览器进行缓存。
【琪姐自信】


2022/03/05

我曾经被问过一道面试题。一开始是问我状态码,后来就问到我304状态码你了解过吗?
后来面试官提示我是属于这个浏览器缓存的问题。
下面是我的一个理解,也是用比较通俗的话来解释这个问题
浏览器缓存可以有效减缓服务器的压力。

强缓存与协商缓存

服务器响应304这是协商缓存。

浏览器缓存有两种,一种是强缓存,一种是协商缓存。

浏览器请求一个未被缓存过的资源时,服务器在响应的同时,会在响应头内加上etag(资源的编号,可以认为就是资源的唯一标识,资源没有发生改变这个编号就不会发生改变),Cache-Control(记录了有效时间),Last-Modified(这个资源上次被修改的时间)等响应字段,这是服务器的一个缓存指令,浏览器看到这些字段就会对响应结果进行缓存,这是浏览器自发完成的,在缓存资源的同时并且记录缓存的有效时间,这个时间在Cache-Control的max-age里记录,还会记录资源的编号etag,以及资源上次被修改的时间last-modified。

当下一次再请求相同的资源时,浏览器会先从缓存里找,如果该资源有缓存并且没有过期,那就命中缓存,浏览器会直接从缓存里拿,而不会发送请求给服务器,不仅减少流量的消耗,也降低了服务器的压力,这属于是强缓存。响应码是200.

但是如果浏览器根据资源的一些记录信息,如果发现请求的资源已经过期了,浏览器会向服务器发出请求询问这个缓存是否可以用,

这个请求携带了If-Modified-Since(对应 请求头的if-modified)和if-none-match(对应请求头的etag),以此询问服务器这个缓存是否有效。那么服务器就根据字段以及资源的修改情况判断资源是否有效,如果有效,服务器会携带新的缓存指令告诉浏览器,这个缓存还可以用,并且响应304状态码,这样的响应是没有响应体的,是告诉浏览器可以继续使用缓存,让它更新缓存资源的一些信息。

如果缓存无效了,那么结果就跟第一次请求一样,服务器响应200并且携带缓存指令和响应体,告诉浏览器资源过期了,需要更新缓存。这样浏览器因缓存过期而询问服务器是否可以使用缓存的情况就是协商缓存。

If-None-MatchEtag通过资源编号来判断资源是否过期【优先】

If-Modified-SinceLast-Modified 通过资源最近上次修改的时间来判断资源是否过期

服务器的响应头

Cache-Control: max-age=3600
ETag: W/"121-171ca289ebf"
Date: Thu, 30 Apr 2020 12:39:56 GMT
Last-Modified: Thu, 30 Apr 2020 08:16:31 GMT

这个响应头表达了下面的信息:

  • Cache-Control: max-age=3600,我希望你把这个资源缓存起来,缓存时间是3600秒(1小时)
  • ETag: W/"121-171ca289ebf",这个资源的编号是W/"121-171ca289ebf"资源文件的hash,只要资源的内容不发生改变,资源的编号就不会发生改变
  • Date: Thu, 30 Apr 2020 12:39:56 GMT,【Date:是本次请求生成消息的具体时间和日期】我给你响应这个资源的服务器时间是格林威治时间2020-04-30 12:39:56
  • Last-Modified: Thu, 30 Apr 2020 08:16:31 GMT这个资源的上一次修改时间是格林威治时间2020-04-30 08:16:31

而后面如果缓存失效,就会浏览器就会在请求头中携带以下字段询问服务器是否可以使用缓存

If-Modified-Since: Thu, 30 Apr 2020 08:16:31 GMT
If-None-Match: W/"121-171ca289ebf"

Expire

http1.0版本中,是通过Expire响应头来指定过期时间点的,例如:

Expire: Thu, 30 Apr 2020 23:38:38 GMT

到了http1.1版本,已更改为通过Cache-Controlmax-age来记录了。

本文标签: 缓存浏览器状态