过去没太研究过HTTP,最近有空,看了一些。本文主要讨论浏览器缓存以及304状态码的一些知识,在这里做一个分享,这里先上一张HTTP请求流程图:

Alt text

一、详细讨论

1、是否禁止缓存

禁止缓存指的是缓存中不得存储任何关于客户端请求和服务端响应的内容。每次由客户端发起的请求都会下载完整的响应内容。

在请求头中,

  1. Cache-Control: no-cache
  1. Pragma: no-cache
都可以禁止缓存,

但两者也有区别,

  1. Pragma: no-cache
可以兼容
  1. http 1.0
,而
  1. Cache-Control: no-cache
  1. http 1.1
提供的。因此,
  1. Pragma: no-cache
可以应用到
  1. http 1.0
  1. http 1.1
,而
  1. Cache-Control: no-cache
只能应用于
  1. http 1.1

2、是否检查本地副本是否过期

是否检查本地版本是否过期主要由

  1. no-cache
  1. must-revalidate
这两个值控制,其中:

    1. no-cache
    : 告诉浏览器、缓存服务器,不管本地副本是否过期,使用资源副本前,一定要到源服务器进行副本有效性校验。
    1. must-revalidate
    :告诉浏览器、缓存服务器,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验。

3、本地副本是否过期

想要知道本地副本是否过期,我们就需要了解缓存的过期机制:

(1)、过期机制中,最重要的指令是

  1. max-age=<seconds>
,它表示资源能够被缓的最大时间;它通常会和
  1. must-revalidate
一起使用,使用起来就像下面这样:

  1. Cache-Control: max-age=60, must-revalidate

(2)、如果不含有

  1. max-age
属性,则会去查看是否包含Expires属性,,通过比较Expires的值和头里面Date属性的值来判断是否缓存还有效。

Alt text

(3)、如果

  1. max-age
  1. expires
属性都没有,找找头里的 Last-Modified 信息。如果有,缓存的寿命就等于头里面
  1. Date
的值减去
  1. Last-Modified
的值除以10(注:根据rfc2626其实也就是乘以10%)。

Alt text

4、如果本地副本没有过期

如果本地副本没有过期,则会直接重缓存中读取资源,并返回200状态码。

Alt text

5、如果本地副本过期

如果本地副本过期,则会进行到源服务器进行有效性校验的前期准备。

首先,会在请求头里寻找If-None-Match字段,其值为服务器上次返回的ETag响应头的值:

Alt text
Alt text

如果请求头里没有If-None-Match字段,则会在请求头中寻找If-Modified-Since字段,其值为服务器上次返回的Last-Modified响应头中的日期值:

Alt text
Alt text

如果

  1. If-None-Match
  1. If-Modified-Since
都没有,则会直接向服务器请求数据。

6、到源服务器进行有效性校验

如果请求头中带有

  1. If-None-Match
  1. If-Modified-Since
,则会到源服务器进行有效性校验,如果源服务器资源没有变化,则会返回304;如果有变化,则返回200;

7、上述的一些流程还可以用下图来表示

Alt text

二、补充

私有缓存和公共缓存

  1. Cache-Control
还有两个值:
  1. private
  1. public
,其中:

  1. public
指令表示该响应可以被任何中间人(比如中间代理、CDN等)缓存。若指定了
  1. public
,则一些通常不被中间人缓存的页面(因为默认是
  1. private
)(比如 带有HTTP验证信息(帐号密码)的页面 或 某些特定影响状态码的页面),将会被其缓存。

  1. private
则表示该响应是专用于某单个用户的,中间人不能缓存此响应,该响应只能应用于浏览器私有缓存中。

三、参考文档

HTTP协议
MDN
segmentfault网站上'赵雍'的回答
'紫云飞'的博客