文章目录
一、前言
vue 项目打包部署上线之后,每一次都会有浏览器缓存问题,导致系统用户访问上个迭代批次的旧资源(css/js
资源),若当前迭代批次项目包中不存在旧资源,系统就是出现404错误信息,需要系统用户手动清除缓存才能解决以上问题,导致用户体验非常不好。
注⚠️:以下说的浏览器缓存是指http缓存。
http缓存是基于HTTP协议的浏览器文件级缓存机制。即针对文件的重复请求情况下,浏览器可以根据协议头判断从服务器端请求文件还是从本地读取文件。
1.1 什么是浏览器缓存
浏览器缓存(Browser Caching)机制是为了节约网络资源提升页面渲染性能,浏览器在用户磁盘上会对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,进而提升页面性能。
1.2 浏览器缓存类型
- 缓存协商:
Last-modified
,Etag
- 彻底缓存(强制缓存):
cache-control
,Expires
注⚠️:关于
Cache-Control: max-age=秒
和Expires
Expires = 时间
,设置以分钟为单位的绝对过期时间,HTTP 1.0 版本,缓存的载止时间,允许客户端在这个时间之前不去检查(发请求);
max-age = 秒
,HTTP 1.1版本,资源在本地缓存多少秒。
如果max-age
和Expires
同时存在,则被Cache-Control:max-age
覆盖。Expires
的一个缺点: 就是返回的到期时间是服务器端的时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大,那么误差就很大,所以在HTTP 1.1版开始,使用Cache-Control: max-age=秒
替代。Expires =max-age + “每次下载时的当前的request时间”,所以一旦重新下载的页面后,expires
就重新计算一次,但last-modified
不会变化.
1.3 浏览器缓存的优势与劣势
优势:
- 节约网络资源,提高网络效率;
- 减少页面资源请求数,降低服务器压力,减少服务器负担;
缺点:
- 缓存没有清理机制;
- 占用硬盘空间;
- 页面缓存,导致页面样式、图片或脚本等未能及时更新展示;
1.4 浏览器缓存机制
查阅这里:https://www.cnblogs.com/vajoy/p/5341664.html
还有这里:https://blog.csdn.net/u014590757/article/details/80140654
还有这里:https://www.jianshu.com/p/1a1536ab01f1
还有:https://www.cnblogs.com/kevingrace/p/10459429.html
二、问题分析
页面在浏览器中进行渲染时,基于浏览器缓存机制,当用户访问之前访问过的系统页面时,浏览器会加载之前已经缓存的页面资源。
vue项目使用webpack
进行编译,生产环境核心配置文件webpack.prod.conf.js
配置的js资源文件生成策略如下:
output: {
// 打包后的文件放在dist目录里面
path: config.build.assetsRoot,
// 文件名称使用 static/js/[name].[chunkhash].js, 其中name就是main,chunkhash就是模块的hash值,用于浏览器缓存.
filename: utils.assetsPath('js/[name].[chunkhash].js'),
// chunkFilename是非入口模块文件,也就是说filename文件中引用了chunckFilename
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
....
// extract css into its own file
new ExtractTextPlugin({
// 生成独立的css文件,下面是生成独立css文件的名称
filename: utils.assetsPath('css/[name].[contenthash].css')
}),
其中,chunkhash
与contenthash
的区别详参博文《Vue进阶(七十):了解 webpack 的 hash、chunkhash、contenthash》。
no-cache
浏览器会缓存,但刷新页面或者重新打开时会请求服务器,服务器可以响应304,如果文件有改动就会响应200。no-store
浏览器不缓存,刷新页面需要重新下载页面。
三、解决方案
在 HTTP 响应头中添加缓存控制的指令来控制浏览器缓存。修改index.html
的内容,可以使用以下缓存请求指令,让所有的css/js
资源重新加载:
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta http-equiv="pragram" content="no-cache">
<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="expires" content="0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
</head>
其中,
-
Cache-Control
表示控制缓存的行为; -
Pragma
表示报文指令。Pragma
是HTTP/1.1
之前版本的历史遗留字段,仅作为与HTTP/1.0
的向后兼容而定义。所有的中间服务器如果都能以HTTP/1.1
为基准,那直接采用Cache-Control: no-cache
指定缓存的处理方式是最为理想的。但要整体掌握全部中间服务器使用的 HTTP 协议版本却是不现实的。因此,发送的请求会同时含有Pragma: no-cache
与Cache-Control: no-cache
两个首部字段。 -
expires
表示缓存的载止时间,允许客户端在这个时间之前不去检查(发请求); -
must-revalidate
表示可缓存但必须再向源服务器进行确认。使用must-revalidate
指令,代理会向源服务器再次验证即将返回的响应缓存目前是否仍然有效。若代理无法连通源服务器再次获取有效资源的话,缓存必须给客户端一条504
(Gateway Timeout)状态码。另外,使用must-revalidate
指令会忽略请求的max-stale
指令(即使已经在首部使用了max-stale
,也不会再有效果)。
此外,还有no-transform
配置参数表示代理不可更改媒体类型。使用 no-transform
指令规定无论是在请求(客户端向代理发请求,代理响应)还是响应(源服务器向代理发响应,代理缓存)中,缓存都不能改变实体主体的媒体类型。这样做可防止缓存或代理压缩图片等类似操作。
注⚠️:
no-cache
从字面意思上很容易误解成为不缓存,但事实上no-cache
代表不缓
存过期资源,缓存会向源服务器进行有效性确认后处理资源,也许称为do-notserve- from-cache-without-revalidation
更合适。no-store
才是真正地不进行缓存!no-store
会导致浏览器禁用缓存,no-store
用于防止重要、保密信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。页面渲染需要重新下载页面关联资源,进而导致网路带宽占用过高,页面渲染性能下降,内存占用过高等问题发生。建议非必要不使用该参数配置!Cache-Control
指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control
并不会修改另一个消息处理过程中的缓存处理过程。
疑问:在vue项目中, 应用Cache-Control
可否实现指定特定页面实现请求和响应遵循的缓存机制?
答:
四、延伸阅读: HTTP 状态码汇总
4.1 1xx(临时响应)
表示临时响应并需要请求者继续执行操作的状态代码。
- 100 (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
- 101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。
4.2 2xx (成功)
表示成功处理了请求的状态代码。
- 200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
- 201 (已创建) 请求成功并且服务器创建了新的资源。
- 202 (已接受) 服务器已接受请求,但尚未处理。
- 203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
- 204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
- 205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
- 206 (部分内容) 服务器成功处理了部分 GET 请求。
4.3 3xx (重定向)
表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
- 300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
- 301 (
永久移动
) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。 - 302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
- 303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
- 304 (
未修改
) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。 - 305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
- 307 (
临时重定向
) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
4.4 4xx(请求错误)
这些状态代码表示请求可能出错,妨碍了服务器的处理。
- 400 (错误请求) 服务器不理解请求的语法。
- 401 (
未授权
) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。 - 403 (
禁止
) 服务器拒绝请求。 - 404 (
未找到
) 服务器找不到请求的资源。 - 405 (方法禁用) 禁用请求中指定的方法。
- 406 (不接受) 无法使用请求的内容特性响应请求的网页。
- 407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
- 408 (请求超时) 服务器等候请求时发生超时。
- 409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
- 410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
- 411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
- 412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
- 413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
- 414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
- 415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
- 416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
- 417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
4.5 5xx(服务器错误)
这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
- 500 (服务器内部错误) 服务器遇到错误,无法完成请求。
- 501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
- 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
- 503 (
服务不可用
) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。 - 504 (
网关超时
) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。 - 505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。