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吧。

相关推荐
好好风格6 小时前
宝塔面板 HTTPS 端口证书不生效排查记录
linux·运维·nginx
宋冠巡8 小时前
OpenEuler 系统下 Nginx 安装配置与管理指南(基于 OpenEuler 22.03 LTS SP4)
nginx·openeuler
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ9 小时前
nginx部署教程
运维·网络·nginx
tongluowan00713 小时前
负载均衡之硬件与软件层面的异同
运维·nginx·负载均衡·f5
宋冠巡13 小时前
华为云开发桌面OpenEuler搭建Nginx服务器实操记录
服务器·nginx·华为云
Dxy12393102161 天前
为什么开了 `open_file_cache` 图片会不显示?
nginx
念何架构之路1 天前
接入LVS+Nginx和服务发现
nginx·服务发现·lvs
ThinkPet2 天前
记事-vue3项目部署Jenkins实现CICD流程
运维·nginx·jenkins·jenkinsfile·cicd流水线
零壹AI实验室2 天前
AI发现潜伏18年的NGINX高危漏洞:CVE-2026-42945完整技术分析
运维·人工智能·nginx