Nginx针对前端静态资源的缓存处理

  当用户上报一个线上的bug后,开发者修改前端代码的bug上新后,用户反映问题依旧存在的问题...这种情况是不是曾经遇到过,这个问题跟浏览器的缓存机制有很大关系(强制缓存和协商缓存,这里我就不介绍具体的缓存机制了,网上资料一搜一大把,并且讲的很详细),这里我来说下我们是如何解决这个问题的。。。

  最简单粗暴的办法就是禁止强制缓存,我们本地开发的时候经常打开chrome这个功能,启用方法如下,这样我们每次刷新页面都是最新的代码,浏览器不会缓存任何静态资源(不知道这么说是不是真的合理...)

  

  当然这种方法是不使用于生产环境的情况:用户每次打开页面都请求所有的资源(假设我们每次不会改所有文件),那每次打开太慢了,这你受的了吗?(陈震腔)。我们在生产环境是强制缓存和协商缓存并用的,其实大部分资源走协商缓存,只有少数文件禁止强制缓存(其中就包括*.html文件)。

  我们知道浏览器请求资源是根据url来判定的,如果url变了,就会使本地缓存失效,向服务器请求新的资源,我们现在在使用的前端框架大部分使用webpack构建项目,而webpack中的loader提供针对css和js文件添加hash值得方法,这样我们在发布新版本后,就会使浏览器缓存失效,从而用户能获取新的资源...但是index.html文件就悲催了(我没见过有对html文件添加hash值的...),针对html文件的缓存的策略一般是禁止强制缓存,每次请求都向服务器请求最新的资源(听说大厂spa基本都是这样,我看掘金网这样的...)。然而针对html强制不缓存有两种方法:

  第一种方法就是在html文件中添加meta标签,告诉浏览器强制不缓存此文件。这种方法有一个致命问题就是添加的meta只有浏览器认识,如果中间环节恰好有缓存服务器(根本不解析不认识此标签),缓存服务器是会缓存的....,其他的问题就应该浏览器的兼容性问题,毕竟这html5的新标签。

<meta http-equiv=Cache-Control content="no-cache, no-store, must-revalidate">
<meta http-equiv=Pragma content=no-cache>
<meta http-equiv=Expires content=0>

  第二种方法就是在nginx服务器location配置不缓存html类型的文件。

location ~* \.(html)$ {
    add_header  Cache-Control  "private, no-store, no-cache, must-revalidate, proxy-revalidate";
}

  注:Cache-Control设置为  max-age=no-cache  服务端还是会返回304,只有设置成  no-store  才是强制不缓存。

 

  对于vue生产环境生成的其他文件,比如image、css、js。这些文件的名称通常会加入MD5 hash后缀,我们可以设置为协商缓存:

location ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|ogg|ogv|webm|htc|xml|woff)$ {
    add_header Cache-Control max-age=604800;
}

  其实以上方法就可以开头我们提到的问题了...在最后我贴一个nginx针对一个特定文件的强制不缓存策略配置,我们在项目中遇到了,我们使用了一个dyConfig.js,这个文件暂时没想到版本控制加hash办法,这个文件是独立于代码的。。。

  

        location / {
            root   html;
            index  index.html index.htm;
       if ($request_filename ~* .*dyConfig\.js$) { add_header Cache-Control "no-store"; } }

  

  对于location中有前缀匹配的, 比如  ^~/new-electric-bicycle-h5  (以^~ 开头,表示uri以某个常规字符串开头,不是正则匹配) location用法总结

  根据location的匹配优先级如下

  (location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/)

# vue所有资源名称会包含hash值,可以使用浏览器强缓存
location ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|ogg|ogv|webm|htc|xml|woff)$ {
    add_header Cache-Control max-age=604800; # 不起作用
}

# html文件因为名称不会改变,所以使用协商缓存,no-cache表示每次都请求文件,不然会返回304
location ~* \.(html)$ {
    add_header  Cache-Control  max-age=no-cache; # 不起作用
}

location ^~/new-electric-bicycle-h5 {
    alias   /www/;
    try_files  $uri $uri/ @diandongcheh5;

    # 前端配置文件dynamicConf.js,强制不缓存
    if ($request_filename ~* .*dynamicConf\.js$) {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; # 有用
    }
}

location @diandongcheh5 {
    rewrite ^/(new-electric-bicycle-h5)/(.+)$ /$1/index.html last;
}

  

  下边的2个location,属于路径模糊匹配,会大于上边2个location(有注释的,属于正则匹配)对于这种情况,我们必须使用 if 语法来使上边的起作用

location ^~/new-electric-bicycle-h5 {
    alias   /www/;
    try_files  $uri $uri/ @diandongcheh5;

    if ($request_filename ~* \.(html)$) {
        add_header  Cache-Control  "private, no-store, no-cache, must-revalidate, proxy-revalidate"; # 起作用
    }

    if ($request_filename ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|ogg|ogv|webm|htc|xml|woff)$) {
        add_header Cache-Control max-age=604800; # 起作用
    }

    # 前端配置文件dynamicConf.js,强制不缓存(此条根据js文件名称去判断的,需要放在通用js配置之后,不然会被覆盖)
    if ($request_filename ~* .*dynamicConf\.js$) {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; # 起作用
    }
}

location @diandongcheh5 {
    rewrite ^/(new-electric-bicycle-h5)/(.+)$ /$1/index.html last;
}

 

  最后,提醒下大家,在location中使用if指令要多加小心,if这个指令是有坑的,nginx官方wiki有介绍:If Is Evil

  参考资料:如何解决静态资源的缓存问题

       浏览器缓存看这一篇就够了

       nginx 配置vue项目缓存

                      nginx中location、rewrite用法总结

 
posted @ 2019-12-07 16:26  韩帅  阅读(13274)  评论(0编辑  收藏  举报