vue SPA项目,浏览器和nginx反向代理缓存问题解决实方案

  1. 问题背景
    a.浏览器端在每次发布新的版本时候,总会出现由于单页面项目中index.html文件(200 ok from disk cache 不发送请求,直接取用了本地磁盘缓存)和服务端版本不一致的问题,致使用户不能及时更新,须要经过手动刷新来强制从服务端更新文件。


    b.补充一下,服务端和浏览器之间架构。

  2. 三级缓存问题
    上述,咱们看到浏览器没有发出请求直接从磁盘中取出index.html文件,这实际上是二级缓存。 
    当浏览器访问的服务器没有设置缓存时,浏览器先200 OK from memory cache,若是浏览器缓存中没有该文件,那么浏览器会200 OK from disk cache 从磁盘中找改文件,若是还找不到,浏览器会从服务端请求该文件下载使用。css

  3. Last-Modified/If-Modified-Since
    a.当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个Last-Modified标记着文件在服务器端最后被修改的时间。

    b.浏览器第二次请求上次请求过的url时,浏览器会在HTTP请求头添加一个If-Modified-Since的标记,用来询问服务器该时间以后文件是否被修改过。html

  4. Etag/If-None-Match
    a.当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个Etag,存放着服务器端生成的一个序列值。

    b.浏览器第二次请求上一次请求过的url时,当浏览器第一次请求一个url时,服务器端的返回状态码为200,同时HTTP响应头会有一个Last-Modified标记着文件在服务器端最后被修改的时间。

  5. 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的一种补充、完善。

  6. 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头。复制代码
  7. 在设置Expires、Etag/If-None-Match、Last-Modified/If-Modified-Since缓存机制下,浏览器第一次请求和第二次请求缓存机制
    a.第一次请求

    b.第二次请求
    vue

  8. 用户操做与缓存
  9. 基于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文件,捕捉到以后设置以下:

    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/;               
          } 复制代码

    可是这样是捕捉不到index.html的,没法控制index.html的缓存。
    缘由分析,是由于咱们在捕捉过程没有一个文件路径是含有.html后缀名的,所以没法过滤出index.html加以设置。

    c.解决方案
    咱们没法经过捕捉含有.html后面的路径,可是咱们知道“/aa/”所对应的文件就是index.html,因此咱们来捕捉这个“/aa/”路径,且不捕捉该路径下子级文件(这样把子文件夹中的js、css、img、font等静态文件也设置来),配置以下:

    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/;           
          } 复制代码
    如此,咱们就能简单的过滤出index.html,并加以设置缓存。
    设置完成后浏览器第一次加载:


    设置完成后浏览器第二次加载:


    经过以上设置,咱们能够很轻松的解决了浏览器和服务器之间的缓存问题。

    有建议或问题能够加群qq交流535798405
相关文章
相关标签/搜索