介绍
http中的某些字段规定了客户端和服务器之间应该如何配合起来实现缓存机制,这样一来,就极大的缓解了服务器的压力,因为很多的请求都是可以在客户端这边直接从缓存中拿到数据的,而不需要访问服务器这边或者就算访问到了服务器,服务器这边发现资源并没有改动,则直接不返回消息体,状态码给个304,让客户端这边从缓存中读取资源。
正文
这些字段名主要的大概有以下几个,我将它们用请求头和响应头中的字段来分别介绍:
请求头:if-modified-since,if-none-match,cache-control,pragma
响应头:cache-control,etag,last-modified,date,expires
接下来我将一一讲解以上字段是什么意思。
首先,请求肯定是由客户端这边发起的,第一次请求的时候,客户端这边的请求头是没有携带这些信息的,也就是说这是一个普通的请求,如果服务器觉得当前请求的资源不会怎么变动,就会在这一次请求中的响应头里添加一些信息,告诉请求方,你请求的这个资源可以把它缓存起来,到时候你再次请求的时候,就不要再请求我了,直接拿缓存就好了(一般来说缓存的都是静态资源如:js,css,img之类的)。
那么,服务器这边会在响应头中添加以下字段:
cache-control: max-age=3600
,我希望你把这个资源缓存起来,缓存时间是3600秒(1小时)
etag: W/"121-171ca289ebf"
,这个资源的编号是W/"121-171ca289ebf"
date: Thu, 30 Apr 2020 12:39:56 GMT
,我给你响应这个资源的服务器时间是格林威治时间2020-04-30 12:39:56
last-modified: Thu, 30 Apr 2020 08:16:31 GMT
,这个资源的上一次修改时间是格林威治时间2020-04-30 08:16:31
expires: Thu, 30 Apr 2020 12:39:56 GMT
,表示过期时间点(这个字段是http1.0协议中的,目前已经普遍使用的是http1.1协议,cache-control的优先级会更高)
客户端拿到这个响应头一看,就知道服务器那边原来需要把这个资源给缓存起来,于是就按照上面的信息给缓存了起来。
接下来,如果客户端再次请求这个资源(当然得是同一个地址,同一个请求方式),它会先检查是否有缓存过该资源,如果发现有缓存,则会检查缓存是否有效,如果有效,则直接从缓存中拿取资源,根本不会去请求服务器。这时从network栏会看到状态码是200,然后size栏为disk cache
或者memory cache
。如果说缓存失效了,那么就会向服务器发送请了。
但是注意,这一次的请求可不是简单的请求,而是带有一些特殊请求头的请求,它会在请求头中添加如下字段:
if-modified-since:Thu, 30 Apr 2020 12:39:56 GMT
,表示上一次你给我的修改时间是这个时间
if-none-match:W/"121-171ca289ebf"
,表示你上一次给我的etag的值(就是该资源的编号)是这个编号
接下来就看服务器怎么处理了,服务器拿到请求头一看,然后会去拿到这些值去对比,如果发现不一样,则会返回最新的资源,然后返回状态码200,其他那些字段也会跟第一次请求一样,把相应的值返回。那如果发现资源还是没有变,则会返回状态码304,其他字段也是一样,把相应的值返回。
这下又来到了客户端这边,客户端则根据状态码来看是否需要继续从缓存中拿取资源,304则继续拿到缓存的资源,然后把服务器给的那些字段都相应的更新一遍;如果是200的话,则拿到服务器给的最新的资源又缓存起来,还有那些字段也都相应更新一遍。
以上就是http的这么一个大概的缓存机制,下面我会补充一些细节
细节
- 可以看到,在请求头中,我还有两个字段没有提到,分别是
cache-control 和 pragma
,这两个如果放在请求头中,则表示告诉服务器,不要考虑任何缓存,给我一个正常的结果。传递形式为:
cache-control:no-cache
pragma:no-cache
两者的区别就是上面的字段为http1.1协议的,下面的字段为http1.0协议的。
是的,cache-control可以出现在请求头中 - 我们可以发现,服务器返回的
last-modified
和客户端相应的if-modified-since
,
还有服务器返回的etag
和客户端相应的if-none-match
两两是一对,后者的值就是前者的值。
注:etag / if-none-match
优先级高于last-modified / if-modified-since
,同时存在则只有etag / if-none-match
生效。 - 服务器返回的cache-control字段,其实不只是max-age=xxx,这一个值,还可以有下面一个或多个值:
public
: 所有内容都将被缓存(客户端和代理服务器都可缓存)
private
: 所有内容只有客户端可以缓存,cache-control的默认取值
no-cache
: 告知客户端,你可以缓存这个资源,但是不要直接使用它。当你缓存之后,后续的每一次请求都需要附带缓存指令,让服务器告诉你这个资源有没有过期。
no-store
: 告知客户端,不要对这个资源做任何的缓存,之后的每一次请求都按照正常的普通请求进行。若设置了这个值,浏览器将不会对该资源做出任何的缓存处理。 -
所谓的强缓存,就是说缓存还没过期,直接从客户端缓存中拿就行了,根本就没有请求到服务器,而协商缓存就是客户端缓存过期了,带着那两个字段给服务器,由服务器根据这两个字段来决定是否需要继续使用缓存的资源。