当前位置: 首页 > Web前端 > JavaScript

一篇了解浏览器缓存的文章

时间:2023-03-27 17:20:34 JavaScript

和一个小广告,作者自己开发的一个收集优质编程教程和视频的网站(包含大量MOOC系统课程和实战课程),有兴趣的同学可以看看,清平网站www.qingp.net概述http中的缓存控件是“浏览器缓存”。浏览器缓存就是将js、css、img等前端资源缓存到浏览器中。除了浏览器缓存的http设置之外,还有一种方法是在HTML页面中添加。这是告诉浏览器不要缓存当前页面,每次访问都要重启。从服务器获取。但是只有部分浏览器支持,所有的缓存代理服务器都不支持,因为代理本身并不解析HTML内容。当浏览器第一次请求服务器的文件index.html时,服务器发回200OK响应,在响应体中返回文件index.html的内容,服务器会设置一个缓存有效期返回的响应头中的period(在http1.0Expiresheader中设置,在http1.1中设置Cache-Control:max-age=xxx),以及服务器上Last-Modified文件的最后修改时间,以及一个标签文件的etag,一共返回三个响应头。浏览器会在本地保存文件内容和文件的响应头信息。需要注意的是,在现代浏览器中,如果要禁用页面缓存,只需要设置Cache-Control响应头即可,但是必须设置Cache-Control:no-store来禁用页面缓存,no-cache不能禁用缓存。浏览器第二次请求此index.html(相同的URL)。由于本地已经有这个文件的缓存,所以浏览器会检查缓存。如果缓存没有过期(检查Expires或者Cache-Control:max-age,资源的第一次请求时间和Cache-Control设置的有效期,计算一个资源过期时间,然后比较这个过期时间和当前请求时间),然后不向浏览器发送请求,直接取缓存,这时候你会看到一个200OK(fromcache)的响应,此时浏览器和服务器没有任何交互。如果检查到缓存已过期,则向服务器发送请求。请求头会携带两个头,If-Modified-Since和If-None-Match。这两个header的值就是缓存文件中保存的最后一个响应的Last-Modified和Etag的值。服务器获取到请求头中的If-Modified-None和Etag后,会进行资源新鲜度检测,即服务器会根据获取到的文件的修改时间判断文件在服务器上的最后修改时间,判断文件是否被修改,根据Etag判断文件内容是否发生变化。如果这两个判断的结论是文件没有被修改,那么服务器仍然会返回304NotModified响应,但是不会在响应体中返回文件内容。这个响应头告诉浏览器缓存没有变化,直接使用本地缓存。而如果这两个判断有任何一个失败,就说明这个文件在服务器上发生了变化,服务器会接受这个请求,并发回一个200OK响应,这个响应中携带了请求文件的内容。注意两个概念,强缓存和协商缓存。强缓存是本地缓存,即来自内存缓存和来自磁盘缓存。协商缓存是指浏览器向服务器发送请求,请求服务器检查缓存是否过期,如果过期则返回200ok并有新的内容,如果没有过期则返回304not修改的。如果资源已经被缓存,使用强缓存会出现一个问题,即服务器资源发生了变化但是浏览器并不知道它还在使用本地的强缓存。这时候可以改变资源的url(一般是加一个hash值),浏览器发现资源url改变了会重新向服务器请求资源。cache-control有几个关键字,public允许客户端和代理服务器缓存资源。private表示只有客户端可以缓存资源,代理服务器不允许缓存资源。no-cache表示不使用本地缓存,使用协商缓存,即浏览器每次向服务器发送请求,检查缓存是否过期。no-store表示不缓存,所以没有强缓存和协商缓存,服务器每次请求都会返回资源内容。这种缓存机制要么阻止浏览器直接发送请求,要么服务器发送请求后不需要返回完整的请求(响应体不需要携带文件数据)。前者是为了减少http请求的次数,后者是为了减少请求的带宽。即使响应头设置了Cache-Control指定了max-age缓存有效期,如果在这个有效期内发送请求,响应状态可能是200FromCache或者304NotModified,具体取决于用户browsing浏览器使浏览器发送请求的行为。200FromCache304NotModified以下三种情况不向服务器发送请求,返回的响应为200FromCache1。在浏览器地址栏输入地址,回车M2。通过链接跳转到当前页面3。从当前页面跳转到其他地方后,按浏览器前进/后退按钮重新进入当前页面。具体有两种显示,frommemorycache和fromdiskcache。前者是从内存中获取缓存,后者是从磁盘中获取缓存。请求获取到内容后,会将内容缓存到本地磁盘和浏览器内存中。一旦浏览器关闭,内存就被释放,内存缓存就不存在了。此时只从磁盘中取缓存,磁盘缓存会再次加载到浏览器内存中,下次先从内存中取缓存。.只有以下一种情况向服务器发送请求,服务器会返回304NotModified1.通过刷新按钮刷新当前页面。在本例中需要注意的是,如果既没有Etag也没有Last-Modified,则服务器无法进行文件变化检测。也不可能返回304NotModified,至少Etag和Last-Modified其中之一,或者两者同时返回,那么服务端可以检查请求的文件在服务端是否有变化,决定是否返回304NotModified或200确定。与缓存相关的响应头浏览器的缓存机制分为两个部分,Freshness和Validation。Fressness就是所谓的缓存新鲜度检测,就是不向浏览器发送请求,是否直接访问本地缓存。验证是向服务器发送请求,服务器检测文件是否发生变化,返回200或304。与Freshness相关的是Expires和Cache-Control响应标头。为什么会有这两个响应头?这是由于历史原因。http1.0中定义了expires,Expires的值是一个明确的过期时间(某年某月某日),后来发现一旦client的时间和server的时间不一致就会出问题。因此在http1.1中加入了Cache-Control来实现更好更精细的缓存控制。比如max-age配置是一个以秒为单位的过期日期,告诉浏览器多长时间不会过期,而不是告诉一个过期日期。和Validation相关的是Last-Modified和Etag,之所以有两个是因为history是个问题。Last-Modified在http1.0中定义,表示文件最后一次被修改的时间。这个协议带来的问题是,一旦内容是动态生成的,这个时间在服务器端可能无法正确生成,即内容是动态生成和变化的,但是文件的时间没有变化。其次,Last-Modified只有秒级精度。如果只是在一秒钟之内修改了文件,这也会导致问题。因此,在http1.1中引入了Etag,其实现方式有所不同。对于动态内容,常规的做法是对动态内容进行Hash计算,返回为Etag。对于静态资源,一般采用inode+mtime来计算。ETag也有其自身的问题,所以在使用中经常关闭ETag。比如同一个文件在不同物理机的inode不一样,导致分布式web系统中访问落在不同物理机时返回的ETag不同,导致200请求304失效降级。解决办法是把inode从ETag算法中剥离出来,只用mtime,但这其实和Last-Modified是一样的。当然你也可以做一些额外的改进,让静态资源的ETag的算法也是通过hash来计算的。但由于普遍采用CDN技术,集群部署中的Etag问题不会造成太大影响。