# 13.HTTP缓存

待整理: https://juejin.cn/post/6976184168333983774#heading-4

# Doctype

< Doctype > 标签申明位于文档的开头,用于告诉浏览器以什么样的方式来渲染页面,有混杂模式和严格模式两种

混杂模式向后兼容,模拟老浏览器,防止浏览器版本过旧不兼容页面

严格模式是将 JS 和排版以浏览器最高的标准运行

# 一、缓存的规则

结论提前说:

  1. 强缓存
    1. Expires:Thu,15 Apr 2010 20:00:00 GMT, 依赖客户端时间,会有问题。(客户端服务端时间不同步、浪涌现象)
    2. Cache-Control:max-age=315360000, public 在本地内存里面读取到上一次发送的 HTTP 请求里面的响应头的数据。没过期就直接用,不依赖客户端时间。状态码: 200(from cache)
      1. no-cache 走协商缓存
      2. no-store 直接不使用缓存,请求最新的
      3. 二者存在会忽略 max-age,会与服务器交互。
  2. 客户端发送Etag / Last-Modified到服务器,服务器进行判断,在服务端设置:(If-None-Match:Etag 是否相同 / if-Modified-Since 是否修改 ),然后 (新内容 200,旧内容 304)
    1. last-modified 缺点:
      1. 只要编辑了,不管内容是否变更都会当成新资源返回
      2. 时间精确到秒,一秒内的修改是检测不到更新的,仍会告知浏览器使用旧缓存
  3. 浏览器的三级缓存原理:
    1. 先去内存看,如果有,直接加载
    2. 如果内存没有,择取硬盘获取,如果有直接加载
    3. 如果硬盘也没有,那么就进行网络请求
    4. 加载到的资源缓存到硬盘和内存

      HTTP 的缓存属于客户端缓存,用于储存一些不经常变化的静态文件(图片、css、js 等)。我们将缓存分为强制缓存和协商缓存

服务器上的数据是会有更新的,我们不能一直使用浏览器的本地缓存,这样就只能一直使用旧数据。我们希望当服务器的数据发生更新时,浏览器会请求更新数据,如果服务器上的数据没有更新我们就使用本地数据,这样能节省因网络请求而产生的资源浪费。 在这里插入图片描述 明确两点:

1、浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识

2、浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中 在这里插入图片描述

# 1、强制缓存

当缓存数据库中已有所请求的数据时。客户端直接从缓存数据库中获取数据。当缓存数据库中没有所请求的数据时,客户端的才会从服务端获取数据。

(虽然没有发出真实的 http 请求)请求状态码返回是 200

关键词:不发送请求

强缓存就是强制缓存,直接读取浏览器缓存。如果在服务器响应的头部字段中设置了cache-control:max-age=xxx,public/private/immutable,都有强制缓存,只要缓存的有效时间(xxx 秒)没过,就直接读取浏览器缓存。如果是用户主动刷新页面,会发起 http 请求资源,有额外的请求消耗,但是如果设置的是 immutable 即使用户刷新也直接读取浏览器缓存。

强缓存有两种策略,对应 HTTP1.0,和 HTTP1.1。

# Expires 策略(HTTP1.0)

Expires 是 Web 服务器响应消息头字段,在响应 http 请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。 Expires 设置失效时间,精确到时分秒。 不过 Expires 是 HTTP 1.0 的东西,现在默认浏览器均默认使用 HTTP 1.1,所以它的作用基本忽略。

# Cache-control 策略(重点关注)

Cache-Control 与 Expires 的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过 Cache-Control 的选择更多,设置更细致,如果同时设置的话,其优先级高于 Expires。

http 协议头 Cache-Control : 值可以是 public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age

# 2、协商缓存

客户端会先从缓存数据库中获取到一个缓存数据的标识,得到标识后请求服务端验证是否失效(新鲜),如果没有失效服务端会返回 304,此时客户端直接从缓存中获取所请求的数据,如果标识失效,服务端会返回更新后的数据。

关键词: 协商缓存:200,304,发送请求 Last-Modifined -> If-Modified-Since 修改时间 Etag -> If-None-Match 服务器唯一标识

当浏览器请求资源时发现缓存过期,就会去请求服务器进行协商缓存。在之前的服务器响应的头部中,还有两个字段与协商缓存有关

etag: '5c20abbd-e2e8' last-modified: Mon, 24 Dec 2018 09:49:49 GMT

etag 是一个文件 hash,每个文件唯一。

last-modified 是文件最后更新的时间。在协商缓存时浏览器的请求会携带这两个字段,服务器会根据这两个标识对比判断文件是否更新,如果发生了更新就会返回 200 状态码,和第一次请求资源一样;如果没有更新就会返回 304,调用浏览器缓存

# 二、服务器是如何判断缓存是否失效

  • 与缓存相关的规则信息就包含在相应头中

# img1. 强缓存

# Expires:Thu,15 Apr 2010 20:00:00 GMT

由于服务端时间和客户端时间可能有误差,现在都用Cache-Control

# Cache-Control

Cache-Control 有很多属性,不同的属性代表的意义也不同。

private:客户端可以缓存 public:客户端和代理服务器都可以缓存 max-age=t:缓存内容将在 t 秒后失效 no-cache:需要使用协商缓存来验证缓存数据,no-cache 代表不缓存过期的资源 no-store:所有内容都不会缓存。

# 2. 协商缓存

# 1. Last-Modified

Last-Modified: 服务器在响应请求时,会告诉浏览器资源的最后修改时间

if-Modified-Since: 浏览器再次请求服务器的时候,请求头会包含此字段,后面跟着在缓存中获得的最后修改时间。(修改则传数据)

if-Unmodified-Since: 从字面上看, 就是说: 从某个时间点算起, 是否文件没有被修改

  • 这两个的区别是一个是修改了才下载一个是没修改才下载。
  • Last-Modified 说好却也不是特别好,因为如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变,会因为 Last-Modified 时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。为了解决这个问题,HTTP1.1 推出了 Etag。
# 2. Etag

Etag:服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务器决定)

If-None-Match:再次请求服务器时,浏览器的请求报文头部会包含此字段,后面的值为在缓存中获取的标识。服务器接收到次报文后发现 If-None-Match 则与被请求资源的唯一标识进行对比。

  1. 不同,说明资源被改动过,则响应整个资源内容,返回状态码 200。
  2. 相同,说明资源无心修改,则响应 header,浏览器直接从缓存中获取数据信息。返回状态码 304.

但是实际应用中由于 Etag 的计算是使用算法来得出的,而算法会占用服务端计算的资源,所有服务端的资源都是宝贵的,所以就很少使用 Etag 了。

# 三、怎么强制使用协商缓存

# 1. Cache-Contro:no-coach

  • (还是会缓存,只不过每一次都要去浏览器判断数据是否更新)

# 2. Ctrl+F5

# 3. Expires = 0 /-1

# 4. 浏览器勾选:disable cache

# 四、缓存的优点

  1. 减少了冗余的数据传递,节省宽带流量
  2. 减少了服务器的负担,大大提高了网站性能
  3. 加快了客户端加载网页的速度 ------- 这也正是 HTTP 缓存属于客户端缓存的原因。

# 五、不同刷新的请求执行过程

  1. 浏览器地址栏中写入 URL,回车 浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)
  2. F5 F5 就是告诉浏览器,别偷懒,好歹去服务器看看这个文件是否有过期了。于是浏览器就胆胆襟襟的发送一个请求带上 If-Modify-since。
  3. Ctrl+F5 告诉浏览器,你先把你缓存中的这个文件给我删了,然后再去服务器请求个完整的资源文件下来。于是客户端就完成了强行更新的操作.
Last Updated: 6/3/2024, 1:08:34 AM