前言

HTTP缓存不管是在面试中,还是实际开发中都是重中之重。了解HTTP缓存不仅可以轻松自如应对面试,而且也是在实际开发中对性能优化不可或缺的手段。

客户端缓存

缓存不仅可以存在于缓存服务器内,还可以存在客户端浏览器中。通常把客户端缓存称为临时网络文件。浏览器缓存如果有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取。另外,和缓存服务器相同的一点是,当判定缓存过期后,会向源服务器确认资源的有效性。若判断浏览器缓存失效,浏览器会再次请求新的资源。

ps:对于前端开发来说,我们只需要关注客户端缓存即可

浏览器第一次请求资源时,必须请求所有的资源,然后根据响应的header内容来决定,如何缓存资源。一般而言缓存可以分为强缓存和协商缓存两种。

强缓存

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

协商缓存

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

HTTP报文组成

首先,在了解HTTP缓存之前,我们有必要先了解HTTP报文的主要组成部分。

1、HTTP请求报文是由方法、URL、HTTP版本、HTTP首部字段等部分构成。

2、HTTP响应报文由HTTP版本、状态码、HTTP首部组成。

在报文众多字段中,HTTP首部字段包含的信息最为丰富的,它是构成HTTP报文的要素之一。跟缓存有关的属性也包含在这里面。

首部字段

首先,我们的先了解首部字段有哪些?一般可以分为通用首部字段、请求首部字段、响应请求字段、实体首部字段,由于本文谈论的是缓存相关的,所以在这里只列举了中跟缓存相关的字段名。

通用首部字段

请求报文和响应报文都会使用的首部,主要的缓存相关字段:

Cache-Control:控制缓存的行为。

通过指定首部字段Cache-Control的指令,就能操作缓存的工作机制,一般可以分为缓存请求指令和缓存响应指令。

1、缓存请求指令

  • no-cache:强制向源服务器再次验证
  • no-store:不缓存请求或者响应的任何内容
  • max-age = '秒':响应的最大Age值(缓存过期时间)
  • only-if-cached:从缓存获取资源

2、缓存响应指令

  • public:表示缓存的版本可以被代理服务器或者其他中间服务器识别。
  • private:意味着这个文件对不同的用户是不同的。只有用户自己的浏览器能够进行缓存,公共的代理服务器不允许缓存。
  • no-cache:强制浏览器提交一个http请求到源服务器进行确认。http请求没有减少,会减少一个响应体(文件内容),这种个选项类似弱缓存。
  • max-age: 指定缓存过期的相对时间秒数,max-ag=0或者是负值,浏览器会在对应的缓存中把Expires设置为1970-01-01 08:00:00
  • no-store:不缓存请求或者响应的任何内容

请求首部字段(Request Header

从客户端向服务端发送请求报文时使用的首部,主要的缓存相关字段:

  • If-Match:比较实体标记(ETag
  • If-Non-Match:比较实体标记(与If-Match相反)
  • If-Modified-Since:比较资源更新时间
  • If-UnModified-Since:比较资源更新时间(与If-Modified-Since相反)

响应首部字段(Response Header

从服务器向客户端发送请求报文时使用的首部,主要的缓存相关字段:

  • ETag:资源的匹配信息(数据签名)

实体首部字段

针对请求报文和响应报文的实体部分使用的首部,用于补充内容的更新时间等与实体信息有关的内容,主要的缓存相关字段:

  • Expires:实体主体过期的日期时间
  • Last-Modified:资源最后修改日期时间

Expires和Cache-Control

Expires指定缓存到期GMT的绝对时间,如果设了max-agemax-age就会覆盖expires。如果expires到期需要重新请求。

Cache-Control:这个是http 1.1中为了弥补 Expires 缺陷新加入的。

ps:所有的首部字段都是基于HTTP/1.1的

资源验证

验证是否能使用缓存(协商缓存策略)主要有两种方式:

1、Last-Modified :最后一次修改时间

配合If-Modified-SinceIf-UnModified-Since使用
对比上次修改时间以验证资源是否需要重新修改

last-modified是web服务器认为文件的最后修改时间,last-modified是第一次请求文件的时候,服务器返回的一个属性。

Last-Modified: Sat, 09 Jun 2018 08:13:56 GMT 

第二次请求这个文件时,浏览器把If-Modified-Since发送给服务器,询问该时间之后文件是否被修改过。

If-Modified-Since: Sat, 09 Jun 2018 08:13:56 GMT //  跟Last-Modified的值一样

2、Etag: 数据签名

配合If-Match或者If-Non-Match使用
对比资源的签名判断是否使用缓存
ETag也是首次请求的时候,服务器返回的:

ETag: "8F759D4F67D66A7244638AD249675BE2" // 长这样

If-None-Match也是浏览器发送到服务器验证,文件是否改变的:

    If-None-Match: "8F759D4F67D66A7244638AD249675BE2" // 跟ETag的值一样

而这里Etag主要为了解决 Last-Modified 无法解决的一些问题:

1、一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;

2、某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);

3、某些服务器不能精确的得到文件的最后修改时间。

缓存状态码

  • 200 OK (from cache)是浏览器没有跟服务器确认,直接用了浏览器缓存;
  • 304 Not Modified 是浏览器和服务器多确认了一次缓存有效性,再用的缓存。
  • 304 Not Modified200 OK (from cache) 慢,指的是浏览器还向服务器确认了下 If-Not-Modified,才用的缓存。
  • 412 Precondition failed (预处理错误):if-Unmodified-Since指令,如果文件被修改:则不传输,服务器返回该状态码

浏览器中的操作对缓存的影响:

强制刷新 – 当按下ctrl+F5来刷新页面的时候, 浏览器将绕过各种缓存(本地缓存和协商缓存), 直接让服务器返回最新的资源;

普通刷新 – 当按下F5来刷新页面的时候,浏览器将绕过本地缓蹲来发送请求到服务器, 此时, 协商缓存是有效的

回车或转向 – 当在地址栏上输入回车或者按下跳转按钮的时候, 所有缓存都生效


蛙哇
307 声望20 粉丝