- 问题背景
a.浏览器端在每次发布新的版本时候,总会出现因为单页面项目中index.html文件(200 ok from disk cache 不发送请求,直接取用了本地磁盘缓存)
和服务端版本不一致的问题,导致用户不能及时更新,需要通过手动刷新来强制从服务端更新文件。
b.补充一下,服务端和浏览器之间架构。 三级缓存问题
上述,我们看到浏览器没有发出请求直接从磁盘中取出index.html文件,这其实是二级缓存。
当浏览器访问的服务器没有设置缓存时,浏览器先200 OK from memory cache,如果浏览器缓存中没有该文件,那么浏览器会200 OK from disk cache 从磁盘中找改文件,如果还找不到,浏览器会从服务端请求该文件下载使用。Last-Modified/If-Modified-Since
a.当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个Last-Modified标记着文件在服务器端最后被修改的时间。
b.浏览器第二次请求上次请求过的url时,浏览器会在HTTP请求头添加一个If-Modified-Since的标记,用来询问服务器该时间之后文件是否被修改过。- Etag/If-None-Match
a.当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个Etag,存放着服务器端生成的一个序列值。
b.浏览器第二次请求上一次请求过的url时,当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个Last-Modified标记着文件在服务器端最后被修改的时间。 - Etag 主要为了解决 Last-Modified 无法解决的一些问题:
a.Etag和Last-Modified特点:
1).它们都属于协商缓存,对内容的有效性进行验证。
2).Etag的值通常为文件内容的哈希值;而Last-Modified为最后修改的时间。
3).Last-Modified只能精确到秒,秒之内的内容更新Etag才能检测。
4).文件有时会定时重新生成相同内容,Last-Modified不能很好辨别,某些服务器甚至不能精确的得到文件的最后修改时间。
5).Etag每次服务端生成都需要进行读写操作,而Last-Modified只需要读取操作,Etag的消耗是更大的。
Etag更像是Last-Modified的一种补充、完善。 - Expires
Expires是RFC 2616(HTTP/1.0)协议中和网页缓存相关字段。用来控制缓存的失效日期,要注意的是,HTTP/1.0有一个功能比较弱的缓存控制机制:Pragma,使用HTTP/1.0的缓存将忽略Expires和Cache-Control头。
可以在nginx中设置 expires:-1; 如下
其它配置:location ~ \.(wma|wmv|asf|mp3|mmf|zip|rar|swf|flv)$ { root /var/www/upload/; expires max; }复制代码
expires 指令可以控制 HTTP 应答中的“ Expires ”和“ Cache-Control ”的头标(起到控制页面缓存的作用) 语法:expires [time|epoch|max|pff] 默认值:off expires指令控制HTTP应答中的“Expires”和“Cache-Control”Header头部信息,启动控制页面缓存的作用 time:可以使用正数或负数。“Expires”头标的值将通过当前系统时间加上设定time值来设定。 time值还控制"Cache-Control"的值: 负数表示no-cache 正数或零表示max-age=time epoch:指定“Expires”的值为 1 January,1970,00:00:01 GMT max:指定“Expires”的值为31 December2037 23:59:59GMT,"Cache-Control"的值为10年。 -1:指定“Expires”的值为当前服务器时间-1s,即永远过期。 off:不修改“Expires”和"Cache-Control"的值 expires使用了特定的时间,并且要求服务器和客户端的是中严格同步。 而Cache-Control是用max-age指令指定组件被缓存多久。 对于不支持http1.1的浏览器,还是需要expires来控制。所以最好能指定两个响应头。 但HTTP规范规定max-age指令将重写expires头。复制代码
在设置Expires、Etag/If-None-Match、Last-Modified/If-Modified-Since缓存机制下,浏览器第一次请求和第二次请求缓存机制
a.第一次请求
b.第二次请求- 用户操作与缓存
- 基于vue-cli3.x脚手架下打包的spa项目缓存机制方案
a.思路
spa项目的网站域名映射的ip地址下入口文件是index.html,除此之外,js、css、img、font等等静态文件都是从index.html下加载出来的。
在vue-cli3.x脚手架打包下的js、css、img、font等静态文件名都是包含hash,所以每次打包index.html加载出来的文件都不会出现相同名称文件,因此也不会出现缓存问题。
因此,我们只需要通过配置nginx,设置协商缓存机制,每次发版本后,让浏览器每次使用的index.html,这样js、css、img、font等静态文件都是最新。
本质上,我只需要设置index.html受nginx配置的缓存机制的影响就好了,js、css、img、font等静态文件可以留给浏览器自身的缓存机制来控制,当不是第一次请求js、css、img、font等静态文件时,这些资源文件可以from disk cache/from memory cache
,直接从缓存中取对应的文件,这样大大减少服务器的资源消耗,同时,通过网友文件的加载速度和页面渲染速度。
b.遇到的问题
在nginx配置过程,我们尝试取捕捉index.html文件,捕捉到之后设置如下:
但是这样是捕捉不到index.html的,无法控制index.html的缓存。location ^~ /aa/ { proxy_set_header X-Real-IP $remote_addr; #html 文件不缓存(你也可以设置为协商缓存,但是参考其他大厂方案,一般index.html入口文件都不作缓存,一方面是因为index.html很小基本在1KB左右,另外这个文件内容变化频繁) if ($request_filename ~* ^.*?.(html|htm)$){ expires -1s; add_header Cache-Control no-cache; } proxy_pass http://XXX/aa/; } 复制代码
原因分析,是因为我们在捕捉过程没有一个文件路径是含有.html
后缀名的,因此无法过滤出index.html加以设置。
c.解决方案
我们无法通过捕捉含有.html
后面的路径,但是我们知道“/aa/”所对应的文件就是index.html,所以我们来捕捉这个“/aa/”路径,且不捕捉该路径下子级文件(这样把子文件夹中的js、css、img、font等静态文件也设置来),配置如下:
如此,我们就能简单的过滤出index.html,并加以设置缓存。location ^~ /aa/ { proxy_set_header X-Real-IP $remote_addr; #html 文件不缓存(你也可以设置为协商缓存,但是参考其他大厂方案,一般index.html入口文件都不作缓存,一方面是因为index.html很小基本在1KB左右,另外这个文件内容变化频繁) if ( $request_uri = "/aa/") { expires -1s; add_header Cache-Control no-cache; #add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; } proxy_pass http://XXX/aa/; } 复制代码
设置完成后浏览器第一次加载:
设置完成后浏览器第二次加载:
通过以上设置,我们可以很轻松的解决了浏览器和服务器之间的缓存问题。
有建议或问题可以加群qq交流535798405
vue SPA项目,浏览器和nginx反向代理缓存问题解决实方案
问题背景a.浏览器端在每次发布新的版本时候,总会出现因为单页面项目中index.html文件(200 ok from disk cache 不发送请求,直接取用了本地磁盘缓存)和服务端版本不一致的问题,导致用户不能及时更新,需要通过手动刷新来强制从服务端更新文件。b.补充一下,服务端和浏览器之间架构。三级缓存问题上述,我们看到浏览器没有发出请求直接从磁盘中取出index.html文件,这其实是二级
·
更多推荐
已为社区贡献1条内容
所有评论(0)