什么是web缓存
web缓存主要指的是两部分:浏览器缓存和http缓存。 浏览器缓存:比如,localStorage,sessionStorage,cookie等等。这些功能主要用于缓存一些必要的数据,比如用户信息。比如需要携带到后端的参数。亦或者是一些列表数据等等。 注意,像localStorage,sessionStorage这种用户缓存数据的功能,他只能保存5M左右的数据,多了不行。cookie则更少,大概只能有4kb的数据。 http缓存:Web 缓存是可以自动保存常见文档副本的 HTTP 设备。当 Web 请求抵达缓存时, 如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这 个文档。 http缓存分为强制缓存和协商缓存。
注意,我们的缓存主要是针对html,css,img等静态资源,常规情况下,我们不会去缓存一些动态资源,因为缓存动态资源的话,数据的实时性就不会不太好,所以我们一般都只会去缓存一些不太容易被改变的静态资源。
缓存解决什么问题
- 减少不必要的网络传输,节约宽带(就是省钱)
- 更快的加载页面(就是加速)
- 减少服务器负载,避免服务器过载的情况出现。(就是减载)
强制缓存
基于Expires字段实现的强缓存
Expires字段的作用是,设定一个强缓存时间。在此时间范围内,则从内存(或磁盘)中读取缓存返回。 对于强缓存来说,Expires已经不是实现强缓存的首选。 因为Expires判断强缓存是否过期的机制是:获取本地时间戳,并对先前拿到的资源文件中的Expires字段的时间做比较。来判断是否需要对服务器发起请求。这里有一个巨大的漏洞:“如果我本地时间不准咋办?” 是的,Expires过度依赖本地时间,如果本地与服务器时间不同步,就会出现资源无法被缓存或者资源永远被缓存的情况。现在的项目中,我们并不推荐使用Expires,强缓存功能通常使用cache-control字段来代替Expires字段
基于Cache-control实现的强缓存(代替Expires的强缓存实现方法)
Cache-Control:max-age=N,N就是需要缓存的秒数。从第一次请求资源的时候开始,往后N秒内,资源若再次请求,则直接从磁盘(或内存中读取),不与服务器做任何交互。 Cache-control中因为max-age后面的值是一个滑动时间,从服务器第一次返回该资源时开始倒计时。所以也就不需要比对客户端和服务端的时间,解决了Expires所存在的巨大漏洞。 Cache-control有max-age、s-maxage、no-cache、no-store、private、public这六个属性。
- max-age决定客户端资源被缓存多久。
- s-maxage决定代理服务器缓存的时长。
- no-cache表示是强制进行协商缓存。
- no-store是表示禁止任何缓存策略。
- public表示资源即可以被浏览器缓存也可以被代理服务器缓存。
- private表示资源只能被浏览器缓存。
协商缓存
基于last-modified的协商缓存
基于last-modified的协商缓存实现方式是:
- 首先需要在服务器端读出文件修改时间,
- 将读出来的修改时间赋给响应头的last-modified字段。
- 最后设置Cache-control:no-cache
协商缓存存在两个非常明显的漏洞。这两个漏洞都是基于文件是通过比较修改时间来判断是否更改而产生的。
-
因为是根据文件修改时间来判断的,在文件内容本身不修改的情况下,依然有可能更新文件修改时间(比如修改文件名再改回来),也就有可能文件内容明明没有修改,但是缓存失效了。
-
当文件在极短时间内完成修改的时候(比如几百毫秒)。因为文件修改时间记录的最小单位是秒,所以,如果文件在几百毫秒内完成修改的话,文件修改时间不会改变,这样,即使文件内容修改了,依然不会返回新的文件。
为了解决上述的这两个问题。从http1.1开始新增了一个头信息,ETag(Entity 实体标签)
基于ETag的协商缓存
ETag就是将原先协商缓存的比较时间戳的形式修改成了比较文件指纹。
文件指纹:根据文件内容计算出的唯一哈希值。文件内容一旦改变则指纹改变。
基于Etag协商缓存的流程:
-
第一次请求某资源的时候,服务端读取文件并计算出文件指纹,将文件指纹放在响应头的etag字段中跟资源一起返回给客户端。
-
第二次请求某资源的时候,客户端自动从缓存中读取出上一次服务端返回的ETag也就是文件指纹。并赋给请求头的if-None-Match字段,让上一次的文件指纹跟随请求一起回到服务端。
-
服务端拿到请求头中的if-None-Match字段值(也就是上一次的文件指纹),并再次读取目标资源并生成文件指纹,两个指纹做对比。如果两个文件指纹完全吻合,说明文件没有被改变,则直接返回304状态码和一个空的响应体并return。如果两个文件指纹不吻合,则说明文件被更改,那么将新的文件指纹重新存储到响应头的ETag中并返回给客户端
ETag的缺点:
-
ETag需要计算文件指纹这样意味着,服务端需要更多的计算开销。。如果文件尺寸大,数量多,并且计算频繁,那么ETag的计算就会影响服务器的性能。显然,ETag在这样的场景下就不是很适合。
-
ETag有强验证和弱验证,所谓将强验证,ETag生成的哈希码深入到每个字节。哪怕文件中只有一个字节改变了,也会生成不同的哈希值,它可以保证文件内容绝对的不变。但是,强验证非常消耗计算量。ETag还有一个弱验证,弱验证是提取文件的部分属性来生成哈希值。因为不必精确到每个字节,所以他的整体速度会比强验证快,但是准确率不高。会降低协商缓存的有效性。