近日,发现我打包的js
代码上传到服务器后,并无更新。想到用ng
作了代理,多是ng
缓存的问题,就查资料学习了一下http
(1.1)缓存的东西。css
req
为请求头,res
响应头,C
客户端,S
服务端)// response Headers
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 04 Dec 2019 09:11:07 GMT
Content-Type: text/css
Vary: Accept-Encoding
Last-Modified: Wed, 04 Dec 2019 09:03:18 GMT
ETag: W/"5de77656-2340"
Expires: Wed, 04 Dec 2019 21:11:06 GMT
Cache-Control: max-age=43200
Content-Encoding: gzip
复制代码
res
中为资源过时时间res
中为资源最近修改时间res
中资源的惟一标识符(hash算法生成)req
中的资源最近修改时间req
中的资源标识res
,req
中表示缓存策略req
中经常使用指令字段名称 | 说明 |
---|---|
max-age= | 设置缓存存储的最大周期,超过这个时间缓存被认为过时(单位秒)。与Expires 相反,时间是相对于请求的时间 |
max-stale[=] | C 可接收一个已通过期的资源。设置一个可选的秒数,不接受超过给定时间的资源 |
min-fresh= | C 但愿获取一个能在指定的秒数内保持其最新状态的res |
no-cache | 在发布缓存副本以前,强制要求缓存把请求提交给原始服务器进行验证 |
no-store | 不缓存有关客户端请求或服务器响应的任何内容 |
res
中经常使用指令(req中重复的不列举,详见MDN)字段名称 | 说明 |
---|---|
public | 代表响应能够被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即便是一般不可缓存的内容 |
private | 代表响应只能被单个用户缓存,不能做为共享缓存(即代理服务器不能缓存它)。私有缓存能够缓存响应内容 |
must-revalidate | 一旦资源过时(好比已经超过max-age ),在成功向原始服务器验证以前,缓存不能用该资源响应后续请求 |
proxy-revalidate | 与must-revalidate 做用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略 |
s-maxage= | 覆盖max-age 或者Expires 头,可是仅适用于共享缓存(好比各个代理),私有缓存会忽略它 |
其中Last-Modified
与If-Modified-Since
,ETag
与If-None-Match
是在每次的res,req中配对使用的。html
过程vue
C
端请求app.js ----> S
端。S
端响应app.js 与Expires ----> C
端。(C
端缓存app.js直到Expires)优点nginx
相比于最原始的不带缓存的请求和相应,优点很明显,会直接从缓存中取,减小请求响应次数git
缺陷github
若是app.js在Expires 内发生了改变,C
端呈现的资源不是最新的。web
过程面试
C
端请求app.js ----> S
端S
端响应app.js 与Expires, Last-Modified ----> C
端。(C
端缓存app.js直到Expires,上次修改时间是 Last-Modified)C
端请求S
端,带上If-Modified-Since(等于上一次相应的Last-Modified)S
端用req
中的If-Modified-Since和res
中的 Last-Modified比较。
C
端:你能够继续用本地缓存(304)优点算法
相比与只使用Expires,if app.js发生变化,能够更新缓存,C
端呈现内容为最新,else 不会有新的res
拉一次资源,直接读缓存vue-cli
缺陷
Last-Modified精确到秒,实际中有不少一秒内会完成不少req
和res
,问题呼之欲出
C
端仍是会从缓存中读,呈现内容不是最新vue-cli
开发下,由于某种缘由,代码实际没有修改,但CI/CD重复构建打包了文件,app.js变为了app01.js(build.js生成的不一样版本hash名称),但代码只是名称变化,内容并不变化,却从新拉了一次资源过程
C
端请求app.js ----> S
端S
端响应app.js 与Expires, Last-Modified ,ETag----> C
端。(C
端缓存app.js直到Expires,上次修改时间是 Last-Modified,文件标识是ETag)C
端请求S
端,带上If-Modified-Since(等于上一次相应的Last-Modified)和If-None-Match(等于上一次相应的Etag)
S
端用req
中的If-None-Match和res
中的 Etag比较,忽略掉If-Modified-Since和Last-Modified的比较。(若是Etag变化,Last-Modified必定变化,充分条件)C
端:你能够继续用本地缓存(304)优点
相较于上一种,使得资源变动的验证更加严格。
缺陷
让咱们设想这种状况,咱们频繁的修改app.js,打包构建,处于某种缘由,咱们并不想C
端呈现最新的app.js,而是一段时间后再读取最新的,显然还达不到咱们的要求
过程
C
端请求app.js ----> S
端S
端响应app.js 与Expires, Last-Modified ,ETag, Cache-Control:max-age=43200 ----> C
端。(C
端发现带有 Cache-Control:max-age=43200,忽略Expires*,记住Last-Modified ,ETag)req
发生的时间+ 12h(43200s)),会直接从缓存中取(200)。
C
端请求S
端,带上If-Modified-Since(等于上一次相应的Last-Modified)和If-None-Match(等于上一次相应的Etag)
S
端用req
中的If-None-Match和res
中的 Etag比较,忽略掉If-Modified-Since和Last-Modified的比较。(若是Etag变化,Last-Modified必定变化,充分条件)C
端:你能够继续用本地缓存(304)优点
达到了咱们上个方案达不到的效果
缺陷?
C
端没法主动知道S
端上咱们请求的资源变化,只能被动的从res
中得知,这算缺陷吗?
如何设置不缓存?
ng配置以下:
// 还有多种设置方法,举例一种
// 重启ng不必定当即生效
location / {
access_log /data/nginx/log/xxx.log api;
root /home/www/html;
if ($request_filename ~ .*\.(htm|html)$)
{
add_header Cache-Control no-cache;
}
}
复制代码
打包html
设置meta
标签以下
<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" />
复制代码
meta是用来在HTML文档中模拟HTTP协议的响应头报文。meta 标签用于网页的与中,meta 标签的用处不少。meta 的属性有两种:name和http-equiv。name属性主要用于描述网页,对应于content(网页内容),以便于搜索引擎机器人查找、分类(目前几乎全部的搜索引擎都使用网上机器人自动查找meta值来给网页分类)。这其中最重要的是description(站点在搜索引擎上的描述)和keywords(分类关键词),因此应该给每页加一个meta值。
如何清理缓存?
Nginx企业版提供了purger功能,对于社区版Nginx能够考虑使用ngx_cache_purge
(该方法最好限制其访问权限,如只容许内网能够访问或者须要密码才能访问)github.com/FRiCKLE/ngx…
location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge cache$1$is_args$args;
}
复制代码
PS: 相似宝塔面板这种Ng都自动安装了ngx_cache_purge
模块,如何设置详见下方参考。
找到缓存文件夹,直接kill。
若是发生缓存错误,检查的步骤?
Network
,勾选js,F5
刷新后找到对应的app.xxx.js,比较。若是你发现名称不同,并且res
头部 Last-Modified也不对,那么大几率你传错文件夹了。Server
只是http
(1.1)的部分常见场景,目前到这里已经足够,咱得一步一步来,切勿囫囵吞枣~
思考有限,不免出现疏漏,欢迎诸位指出,集思广益。
欢迎关注个人公众号《web工程师的自我修养》,一块儿交流学习共勉~