• nginx-自动获取最新静态文件


    需求:

    前端每次发版完,有部分前端文件是更新了的,但是客户访问却拿不到最新的前端文件,总不能让每个客户都手动清除浏览器缓存。

    要实现让浏览器自己去获取最新的前端文件。

    原理:

    Nginx给请求的响应头中添加不缓存的策略。

    # 设置缓存策略为不缓存:Http 1.1

    add_header Cache-Control no-cache;

    # 设置缓存策略为不缓存:Http 1.0

    add_header Pragma no-cache;

    # 设置缓存启用和缓存时间:Http 1.0

    add_header Expires 0;  # 缓存时间为0,即立即过期

    为了向下兼容,可以将Http 1.0的配置也写上:

    add_header Pragma no-cache;

    add_header Expires 0;

    优先级从高到低

    Pragma -> Cache-Control -> Expires

    同时出现Pragma和Cache-Control时,以Pragma为准。

    同时出现Cache-Control和Expires时,以Cache-Control为准。

    按文件类型进行缓存:

    而前端文件常见的有:html、js、css等。

    针对不同的文件类型,可以有不同的缓存策略。

    如果你的前端每次发版js和css文件名都会携带hash码,即每次发版后的文件名都不一样,客户端自然能拿到最新。

    那么只需要针对html文件设置不缓存的请求头策略。

    写法一:

    # 前端静态文件

    location ~* \.(gif|jpg|jpeg|png|css|js|ico|eot|otf|fon|font|ttf|ttc|woff|woff2)$ {

        root /var/www/zhian_cloud/;

    }

    # 前端html文件

    location / {

        #  对html文件禁用缓存,任何时候都不缓存,拿到最新的

        add_header Cache-Control 'no-cache, must-revalidate, proxy-revalidate, max-age=0';

        root /var/www/zhian_cloud/;

        index index.html index.htm;

        try_files $uri /index.html;

    }

    写法二:直接匹配html文件,单独添加响应头

        location / {

            index index.html;

            root /var/www/zhian_cloud/;

        

            if ($request_filename ~* .*\.(?:htm|html)$) {

                add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";

            }

            try_files $$uri /index.html;

        }

    Cache-Control

    Cache-Control也是一个通用首部字段,这意味着它能分别在请求头和响应头中使用。

    作为请求头时,可选值有:

    no-cache:

    告知(代理)服务器不直接使用缓存,要求向源站服务器发起请求。

    no-store:

    所有内容都不会被保存到缓存或Internet临时文件中。

    max-age=delta-seconds:

    告知服务器客户端希望接收一个存在时间(age)不大于delta-seconds秒的资源。

    max-stale[=delta-seconds]:

    告知(代理)服务器客户端愿意接收一个超过缓存时间的资源,若有定义delta-seconds则为delta-srconds秒,若没有则为任意超出的时间。

    min-freash=delta-seconds:

    告知(代理)服务器客户端希望接收一个在小于delta-seconds秒内被更新过的资源。

    no-transform:

    告知(代理)服务器客户端希望获取实体数据没有被转换(比如压缩)过的资源。

    only-if-cached:

    告知(代理)服务器客户端希望获取缓存的内容(若有),而不用向源站服务器发去请求。

    cache-extension:

    自定义扩展值,若服务器不识别该值将被忽略。

    作为响应头时,可选值有:

    public:

    表名任何情况下都得缓存该资源(即使是需要http认证的资源)。

    Private[="field-name"]:

    表明返回报文中全部或部分(若指定了field-name则为field-name的字段数据)仅开放给某些用户(服务器指定的share-user,如代理服务器)做缓存使用,其他用户则不能缓存这些数据。

    no-cache:

    不直接使用缓存,要求向服务器发起(新鲜度校验)请求。

    no-store:

    所有内容都不会被保存到缓存或Internet临时文件中。

    max-age=delta-seconds:

    告知客户端该资源在delta-seconds秒内是新鲜的,无需向服务器发请求。

    s-maxage=delta-seconds:

    同max-age,但仅应用于共享缓存(如代理)。

    no-transform:

    告知客户端缓存文件时不得对实体数据做任何改变。

    only-if-cached:

    告知(代理)服务器客户端希望获取缓存的内容(若有),而不用向源站服务器发去请求。

    must-revalidate:

    当前资源一定是向源站服务器发去验证请求的,若请求失败会返回504(而非代理服务器上的缓存)。

    proxy-revalidate:

    与must-revalidate类似,但仅能应用于共享缓存(如代理)。

    cache-extension:

    自定义扩展值,若服务器不识别该值将被忽略。

    public和private的选择

    如果你用了CDN,你需要关注下这个值。CDN厂商一般会要求cache-control的值为public,提升缓存命中率。

    如果你的缓存命中率很低,而访问量很大的话,可以看下是不是设置了private,no-cache这类的值。

    如果定义了max-age,可以不用再定义public,它们的意义是一样的。

    缓存校验

    在缓存中,我们需要一个机制来验证缓存是否有效。比如服务器的资源更新了,客户端需要及时刷新缓存;又或者客户端的资源过了有效期,但服务器上的资源还是旧的,此时并不需要重新发送。缓存校验就是用来解决这些问题的,在http 1.1 中,我们主要关注下Last-Modified 和 etag 这两个字段。

    1、Last-Modified

    服务端在返回资源时,会将该资源的最后更改时间通过Last-Modified字段返回给客户端。客户端下次请求时通过If-Modified-Since或者If-Unmodified-Since带上Last-Modified,服务端检查该时间是否与服务器的最后修改时间一致:如果一致,则返回304状态码,不返回资源;如果不一致则返回200和修改后的资源,并带上新的时间。

    If-Modified-Since和If-Unmodified-Since的区别:

    If-Modified-Since:告诉服务器如果时间一致,返回状态码304。

    If-Unmodified-Since:告诉服务器如果时间不一致,返回状态码412。

    2、etag

    单纯的以修改时间来判断还是有缺陷,比如文件的最后修改时间变了,但内容没变。对于这样的情况,我们可以使用etag来处理。

    etag的方式是这样:服务器通过某个算法对资源进行计算,取得一串值(类似于文件的md5值),之后将该值通过etag返回给客户端,客户端下次请求时通过If-None-Match或If-Match带上该值,服务器对该值进行对比校验:如果一致则不要返回资源。

    If-None-Match和If-Match的区别:

    If-None-Match:告诉服务器如果一致,返回状态码304,不一致则返回资源。

    If-Match:告诉服务器如果不一致,返回状态码412。

    Http状态码304:

    当客户端(通常是浏览器)向web服务器发送一个请求,如果web服务器返回304响应,他不包含任何响应的内容,只是提示客户端缓存的内容是最新的,可以直接在客户端的缓存中获取。这种方法可以节省带宽,避免重复响应。

    用户刷新访问行为

    1、在URL输入栏中输入然后回车/通过书签访问

    可以看到返回响应码是 200 OK (from cache),浏览器发现该资源已经缓存了而且没有过期(通过Expires头部或者Cache-Control头部),没有跟服务器确认,而是直接使用了浏览器缓存的内容。其中响应内容和之前的响应内容一模一样,例如其中的Date时间是上一次响应的时间。

    2、F5/点击工具栏中的刷新按钮/右键菜单重新加载

    F5的作用和直接在URI输入栏中输入然后回车是不一样的,F5会让浏览器无论如何都发一个HTTP Request给Server,即使先前的响应中有Expires头部。

    其中Cache-Control是Chrome强制加上的,而If-Modified-Since是因为获取该资源的时候包含了Last-Modified头部,浏览器会使用If-Modified-Since头部信息重新发送该时间以确认资源是否需要重新发送。 实际上Server没有修改这个index.css文件,所以返回了一个304(Not Modified),这样的响应信息很小,所消耗的route-trip不多,网页很快就刷新了。

    3、Ctl+F5

    Ctrl+F5是彻底的从Server拿一份新的资源过来,所以不光要发送HTTP request给Server,而且这个请求里面连If-Modified-Since/If-None-Match都没有,这样Server不能返回304,而是把整个资源原原本本地返回一份,这样,Ctrl+F5引发的传输时间变长了,自然网页Refresh的也慢一些。我们可以看到该操作返回了200,并刷新了相关的缓存控制时间。

    实际上,为了保证拿到的是从Server上最新的,Ctrl+F5不只是去掉了If-Modified-Since/If-None-Match,还需要添加一些HTTP Headers。

    例如请求头中会添加以下两个字段:

    Cache-Control: no-cache Pragma: no-cache

    按照HTTP/1.1协议,Cache不光只是存在Browser终端,从Browser到Server之间的中间节点(比如Proxy)也可能扮演Cache的作用,为了防止获得的只是这些中间节点的Cache,需要告诉他们,别用自己的Cache敷衍我,往Upstream的节点要一个最新的copy吧。

  • 相关阅读:
    matlab去除图片上的噪声
    Redis 源码简洁剖析 16 - 客户端
    Android Anr traces.txt 最全最完整说明文档
    Swoole 4.8版本的安装
    Vue路由&nodejs环境搭建
    Vue框架背后的故事
    Mybaits一级缓存和二级缓存分别是什么,区别是什么?
    在 Linux 中查找文件的 4 种方式
    【python海洋专题二十四】南海年平均海流图
    网页在线打开PDF_网站中在线查看PDF之pdf.js
  • 原文地址:https://blog.csdn.net/qq_29518275/article/details/134468779