缓存类型
缓存在宏观上可以分为两类:私有缓存和共享缓存。共享缓存就是那些能被各级代理缓存的缓存,私有缓存就是用户专享的,各级代理不能缓存的缓存。
微观上可以分为以下几种:
1. 浏览器缓存
缓存存在的意义就是当用户点击back按钮或者是再次去访问某个页面的时候能够快速的响应。尤其在多页面应用的网站中,如果你在多个页面使用了一张相同的图片,那么缓存这张图片就变得特别的有用。浏览器先向代理服务器发起Web请求,再将请求转发到源服务器。其中浏览器缓存包括强缓存和协商缓存,下文有详细介绍。本文主要侧重点就是针对于浏览器缓存。
2.CDN缓存
CDN缓存一般是由网站管理员自己部署,为了让他们的网站更容易扩展并获得更好的性能。通常情况下,浏览器先向CDN网关发起Web请求,网关服务器后面对应着一台或多台负载均衡源服务器,会根据它们的负载请求,动态将请求转发到合适的源服务器上。从浏览器角度来看,整个CDN就是一个源服务器,从这个层面来说,浏览器和服务器之间的缓存机制,在这种架构下同样适用。
3. 代理服务器缓存
代理服务器就是浏览器和源服务器之间的中间服务器,代理转发响应时,缓存代理会预先将资源的副本(缓存)保存袋代理服务器上。当代理再次接受对相同资源的请求时,就可以不从源服务器那里获取资源,而将之前缓存的资源作为响应返回。
4.数据库缓存
数据库缓存是指,当web应用的关系比较复杂,数据库中的表很多时,如果频繁的进行数据库查询,很容易导致数据库不堪重负。为了提供查询的性能,将查询后的数据放在内存中进行缓存,下次查询时,直接从内存缓存中返回,提高响应效率。
5.应用层缓存
应用层缓存是指我们在代码层面做好的缓存。通过代码逻辑,把曾经请求国的数据和资源等缓存起来,再次需要数据时通过逻辑上的处理选择可用的数据。
浏览器缓存
浏览器缓存就是把一个已经请求过的web资源拷贝一份存储在浏览器中,当下次请求相同的资源时,浏览器会根据缓存机制决定直接使用副本响应访问请求还是再次向服务器发送请求。
和有缓存时候的图:
使用缓存的优点:
1.减少冗余的数据传输
2.减少了服务器端的负担,大大提升了网站的性能
3.加大了客户端加载网页的速度
判断缓存是否过期:
1. 浏览器如何判断缓存是否过期?
浏览器判断缓存是否过期主要是根据Response Header 里面的cache-control 和 expires。当两个都存在时,Cache-Control优先级较高。
Cache-Control
该字段用于控制浏览器在什么情况下直接使用本地缓存而不向服务器发送请求。一般具有以下值:
Cache-directive | 说明 |
---|---|
public | 所有内容都将被缓存(客户端和代理服务器都可缓存) |
private | 内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存) |
no-cache | 必须先与服务器确认返回的响应是否被更改,然后才能使用该响应来满足后续对同一个网址的请求。因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,如果资源未被更改,可以避免下载。 |
no-store | 所有内容都不会被缓存到缓存或 Internet 临时文件中 |
must-revalidation/proxy-revalidation | 如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证 |
max-age=xxx (xxx is numeric) | 缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高 |
expires
该字段用来控制缓存的失效日期。Expires字段声明了一个网页或URL地址不再被浏览器缓存的时间,一旦超过了这个时间,浏览器都应该联系原始服务器。
举例:(如139邮箱的查看邮件)
浏览器缓存将在3600秒(即一小时)之后过期。
expires对应的时间是格林尼治时间,转换为中国时间应该为GMT+8,截止时间也是一小时之后
2. 服务器如何判断缓存是否过期?
Etag
Etag 是URL的Entity Tag,用于标示URL对象是否改变,ETag是一个可以与Web资源关联的记号(token)。
ETags和GET请求的“If-None-Match”头一起使用,这样可利用客户端(例如浏览器)的缓存。
ETag
属性之间的比较采用的是弱比较算法,即两个文件除了每个比特都相同外,内容一致也可以认为是相同的。例如,如果两个页面仅仅在页脚的生成时间有所不同,就可以认为二者是相同的。
使用Etag的作用如下:
1、一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间)
2、某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的
3、某些服务器不能精确的得到文件的最后修改时间;
为此,HTTP/1.1引入了 Etag(Entity Tags).Etag仅仅是一个和文件相关的标记,可以是一个版本标记,比如说v1.0.0或者说"2e681a-6-5d044840"这么一串看起来很神秘的编码。但是HTTP/1.1标准并没有规定Etag的内容是什么或者说要怎么实现,唯一规定的是Etag需要放在""内。 [1]
举例:
ETag和if-none-match
参考:https://www.jianshu.com/p/615d1769b054
1. 什么是MD5?
MD5是一个摘要算法,它可以用来检查下载文件的完整性。
文件在服务器上经过MD5处理的得出来的值,和下载下来经过MD5处理得出来的值作对比,两者相同,即文件下载完整。
ETag需要利用到MD5。
首先在项目中给nodejs安装MD5
npm install md5
2. ETag的实现过程
- ①请求端代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Cache-Control & ETag</title>
<link rel="stylesheet" href="css/default.css?version=1"> <!--比较大的文件,用来测试Cache-Control -->
</head>
<body>
<script src="js/main.js"></script> <!--比较大的文件,用来测试ETag-->
</body>
</html>
- ②客户端首次请求资源(main.js),服务器将文件对应的字符串做MD5处理,然后在把文件的MD5值放入ETag中
if (pathName === '/js/main.js'){
//使用ETag
let string = fs.readFileSync('./js/main.js', 'utf8')
response.setHeader('Content-Type', 'application/javascript; charset=utf8')
let fileMd5 = md5(string)
response.setHeader('ETag', fileMd5)
response.write(string)
response.end()
}
-
③此后客户端每次请求这个资源(main.js),都会带上if-none-match这个key,这个key的value就是在服务器端通过MD5处理后的MD5值
图示
-
④服务器端读取if-none-match的内容,和本次的MD5处理后的内容做对比,如果一样,那么就只返回一个304(所以304指的就是Not Modified,即没有修改),不返回请求内容。如果不一样,就是资源有更新变动,就将其返回,并且写入新的MD5处理后的ETag
if (pathName === '/js/main.js'){
//使用ETag
let string = fs.readFileSync('./js/main.js', 'utf8')
response.setHeader('Content-Type', 'application/javascript; charset=utf8')
let fileMd5 = md5(string)
response.setHeader('ETag', fileMd5)
if(request.headers['if-none-match'] === fileMd5){
//main.js没有更新,没有响应体
response.statusCode = 304
} else{
//有更新,再把新的内容返回
response.write(string)
}
response.end()
}
Cache-Control和ETag的区别
Cache-Control直接是通过不请求来实现,而ETag是会发请求的,只不过服务器根据请求的东西的内容有无变化来判断是否返回请求的资源。
If-Modified-Since与Last-Modified
在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是客户端请求的资源,同时有一个Last-Modified的属性标记此文件在服务器端最后被修改的时间。
Last-Modified格式类似这样:
Last-Modified : Fri , 12 May 2006 18:53:33 GMT
客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头,询问该时间之后文件是否有被修改过:
If-Modified-Since : Fri , 12 May 2006 18:53:33 GMT
二者一致,返回状态码304,请求内容直接从缓存中读取,此时服务器返回的内容为空。
Etag,if-none-match和last-modified,if-Modified-Since共同使用
如果服务器端的资源没有变化,则时间一致,自动返回HTTP状态码304(Not Changed.)状态码,内容为空,客户端接到之后,就直接把本地缓存文件显示到浏览器中,这样就节省了传输数据量。
如果服务器端资源发生改变或者重启服务器时,时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。
以上操作可以保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
用户行为与缓存
浏览器缓存行为还有用户的行为有关!!!
用户操作 | Expires/Cache-Control | Last-Modified/Etag |
地址栏回车 | 有效 | 有效 |
页面链接跳转 | 有效 | 有效 |
新开窗口 | 有效 | 有效 |
前进、后退 | 有效 | 有效 |
F5刷新 | 无效 | 有效 |
Ctrl+F5刷新 | 无效 | 无效 |
最后:参考博客汇总:
https://www.cnblogs.com/tangyuu/p/6396644.html
https://www.jianshu.com/p/b5c805f4e8d1
https://www.cnblogs.com/lovesong/p/5352973.html
https://www.cnblogs.com/skynet/archive/2012/11/28/2792503.html