网络请求会耗费大量时间和请求,如果可以重用为改变的网络资源,对于用户来说可以更快更流畅的查看网页,对于服务器来说减少了很多负荷,所以浏览器缓存是前端优化的重要内容。本文介绍了浏览器缓存的机制和缓存在webpack中的应用。

浏览器缓存

浏览器缓存分为两种类型:

  • 强缓存:也称为本地缓存,不向服务器发送请求,直接使用客户端本地缓存数据
  • 协商缓存:也称304缓存,向服务器发送请求,由服务器判断请求文件是否发生改变。如果未发生改变,则返回304状态码,通知客户端直接使用本地缓存;如果发生改变,则直接返回请求文件。

浏览器缓存机制的过程如下:

强缓存(本地缓存)

强缓存是最彻底的缓存,无需向服务器发送请求,通常用于css、js、图片等静态资源。浏览器发送请求后会先判断本地是否有缓存。如果无缓存,则直接向服务器发送请求;如果有缓存,则判断缓存是否命中强缓存,如果命中则直接使用本地缓存,如果没命中则向服务器发送请求。判断是否命中本地缓存的方法有两种:ExpiresCache-Control

Expires

Expires是http1.0的响应头,代表的含义是资源本地缓存的过期时间,由服务器设定。服务器返回给浏览器的响应头中如果包含Expires字段,浏览器发送请求时拿当前时间和Expires字段值进行比较,判断资源缓存是否失效。如下图所示:

Date代表请求资源的时间,Expires代表资源缓存的过期时间,可以看到服务器设置资源的缓存时间为5分钟。2017-02-10 07:53:19之前,请求这个资源就是命中本地缓存。超过这个时间再去请求则不命中。

Cache-Control

Cache-Control是http1.0中新增的字段。由于Expires设置的是资源的具体过期时间,如果服务器时间和客户端时间不一样,就会造成缓存错乱,比如认为调节了客户端的时间,所以设置资源有效期的时长更合理。http1.1添加了Cache-Control的max-age字段。max-age代表的含义是资源有效期的时长,是一个相对时长,单位为s。

Cache-Control: max-age = 300设置资源的过期时间为5分钟。浏览器再次发送请求时,会把第一次请求的时间和max-age字段值相加和当前时间比较,以此判断是否命中本地缓存。max-age使用的都是客户端时间,比Expires更可靠。如果max-age和Expires同时出现,max-age的优先级更高。Cache-Control提供了更多的字段来控制缓存:

  • no-store,不判断强缓存和协商缓存,服务器直接返回完整资源
  • no-cache,不判断强缓存,每次都需要向浏览器发送请求,进行协商缓存判断
  • public,指示响应可被任何缓存区缓存
  • private,通常只为单个用户缓存,不允许任何共享缓存对其进行缓存,通常用于用户个人信息

协商缓存

协商缓存的判断在服务器端进行,判断是否命中的依据就是这次请求和上次请求之间资源是否发生改变。未发生改变命中,发生改变则未命中。判断文件是否发生改变的方法有两个:Last-Modified、If-Modified-SinceEtag、If-None-Match

Last-Modified、If-Modified-Since

Last-Modified是http1.0中的响应头字段,代表请求的资源最后一次的改变时间。If-Modified-Since是http1.0的请求头,If-Modified-Since的值是上次请求服务器返回的Last-Modified的值。浏览器第一次请求资源时,服务器返回Last-Modified,浏览器缓存该值。浏览器第二次请求资源时,用于缓存的Last-Modified赋值给If-Modified-Since,发送给服务器。服务器判断If-Modified-Since和服务器本地的Last-Modified是否相等。如果相等,说明资源未发生改变,命中协商缓存;如果不相等,说明资源发生改变,未命中协商缓存。

可以看到该请求返回的是304状态码,说明资源的Last-Modified未改变,所以这次请求的Last-Modified和If-Modified-Since是一致的。

Etag、If-None-Match

Last-Modified、If-Modified-Since使用的都是服务器提供的时间,所以相对来说还是很可靠的。但是由于修改时间的精确级别或者定期生成文件这种情况,会造成一定的错误。所以http1.1添加Etag、If-None-Match字段,完善协商缓存的判断。Etag是根据资源文件内容生成的资源唯一标识符,一旦资源内容发生改变,Etag就会发生改变。基于内容的标识符比基于修改时间的更可靠。If-None-Match的值是上次请求服务器返回的Etag的值。Etag、If-None-Match的判断过程和Last-Modified、If-Modified-Since一致,Etag、If-None-Match的优先级更高。

工程中遇到的问题

强缓存的优势很明显,无需向服务器发送请求,节省了大量的时间和带宽。但是有一个问题,缓存有效期内想更新资源怎么办?我在工程中还遇到另外一个问题,一个项目有四个环境,测试环境、开发环境、在线确认环境、在线环境,四个环境的域名相同,这样就会造成四个环境的缓存共用问题。比如先访问了测试环境,index.js被换成到浏览器中,再切换到在线环境,在线环境会请求index.js,此时浏览器就会使用本地缓存中测试环境的index.js,造成代码错乱。

如何使强缓存失效,是问题的关键。通常的解决方法是更新文件名,文件名不一样的话,浏览器就会重新请求资源。我们要保证新发布版本和不同环境中的文件名是不一样的。其中一种方法在文件名后加版本号:

index.js?version=1
index.css?version=1

webpack提供了很简单的方法可以配置缓存。

// webpack.config.js
module.exports = {entry: "main.js",output: {path: "/build",filename: "main.[hash].js"}
};

通过hash占位符,在每次生成打包文件时,都会通过文件内容生成唯一的hash,并添加到输出的文件名中。如果有多个入口文件,可以使用name占位符设置输出:

// webpack.config.js
module.exports = {entry: {main:"main.js",sub:"sub.js"},output: {path: "/dist",filename: "[name].[hash].js"}
};

这时候有一个问题是,此时的hash是根据两个文件的内容来生成的,两个文件名使用的hash是一致的。如果main.js和sub.js只有一个改变,两个文件名都会改变,两个文件都会重新请求,造成资源浪费。webpack提供了chunkhash来代替hash在多入口情况下使用。chunkhash是根据每个入口文件单独生成的哈希值,避免上述情况。

webpack打包动态生成文件名,我们需要动态地把文件引用插入到html启动文件中。html-webpack-plugin可以帮我很好地解决这个问题。html-webpack-plugin可以动态地生成一个html文件,并在html文件中动态插入webpack打包生成的资源文件。

var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpackConfig = {entry: 'main.js',output: {path: '/dist',publicPath: '/dist',filename: 'main.[hash].js'},plugins: [new HtmlWebpackPlugin()]
};

默认在webpackConfig.output.path路径下生成index.html,生成的html文件如下:

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>Webpack App</title></head><body><script src="main.2a6c1fee4b5b0d2c9285.js"></script></body>
</html>

通常html启动文件都有自定义的内容,所以html-webpack-plugin提供了模板功能,template字段设置模板的路径,html-webpack-plugin以template为模板,动态添加webpack打包生成的资源路径。

var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpackConfig = {entry: 'main.js',output: {path: '/dist',publicPath: '/dist',filename: 'main.[hash].js'},plugins: [new HtmlWebpackPlugin({template:'index.html'})]
};

原index.html内容(index.html):

<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><title>stat-front</title><link rel="stylesheet" href="//at.alicdn.com/t/font_ejl5slgdvtg74x6r.css"></head><body><div id="app" class="app-root"><router-view></router-view></div><!-- built files will be auto injected --></body>
</html>

生成的index.html内容(distindex.html):

<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><title>stat-front</title><link rel="stylesheet" href="//at.alicdn.com/t/font_ejl5slgdvtg74x6r.css"></head><body><div id="app" class="app-root"><router-view></router-view></div><!-- built files will be auto injected --><script src="main.2a6c1fee4b5b0d2c9285.js"></script></body>
</html>

最开始的时候静态的index.html在根目录下,webpack-dev-server设置的启动路径就是根目录下的index.html,如果要启动生成的index.html,还需要设置webpackConfig.output.publicPath

var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpackConfig = {entry: 'main.js',output: {path: '/dist',publicPath: '/',filename: 'main.[hash].js'},plugins: [new HtmlWebpackPlugin({template:'index.html'})]
};

这样webpack-dev-server在内存中生成的资源都存放在根目录下,生成的index.html会代替原index.html启动。

博客地址

浏览器缓存和webpack缓存配置相关推荐

  1. 网站优化:浏览器缓存控制简介及配置策略

    每次访问网页,通常浏览器会从服务器下载所 需的资源,例如 HTML 文档.图片.CSS.JavaScript,甚至包括字体文件等.这里面的许多文件(例如图片)都是很少变动的,如果每次都要从服务器重新下 ...

  2. 浏览器缓存:强缓存和协商缓存

    1. 强缓存,不向服务器发请求,直接从本地硬盘(from disk cache/from memory cache)或者内存中获取 2.协商缓存,向服务器发出验证,如果资源无更改,不重新返回资源内容, ...

  3. Varnish缓存代理简介与配置

    一.varnish原理: 1)Varnish简介: varnish缓存是web应用加速器,同时也作为http反向缓存代理.你可以安装varnish在任何http的前端,同时配置它缓存内容.与传统的 s ...

  4. js——浏览器缓存(http缓存)和本地存储

    http缓存链接 http缓存的好处: 事先代码准备: 创建一个http服务 在集成终端中,输入node app.js启动服务 此时,在浏览器中输入localhost:3000,结果如下 新建一个in ...

  5. 浏览器的缓存机制 优点 缺点 协商缓存和强缓存 浏览器缓存过程 如何判断强缓存是否过期

    缓存的优点: 减少了不必要的数据传输,节省带宽 减少服务器的负担,提升网站性能 加快了客户端加载网页的速度 用户体验友好 缺点: 资源如果有更改,会导致客户端不及时更新就会造成用户获取信息滞后 当浏览 ...

  6. DNS 缓存、CDN 缓存、浏览器缓存,JVM DNS 缓存详解

    最近测试遇到修改host文件后,清除浏览器缓存后,重启浏览器后,发现浏览器还是访问老DNS服务,于是网上查查原因,豁然开朗. 这里对互联网上一些文章进行整理,原文可查看参. 1.DNS 缓存 1.1 ...

  7. 浏览器缓存(强缓存和协商缓存)

    什么是浏览器缓存(强缓存和协商缓存) 浏览器缓存 是浏览器将用户请求过的静态资源(html.css.js),存储到电脑本地磁盘中,当浏览器再次访问时,就可以直接从本地加载了,不需要再去服务端请求了. ...

  8. 浏览器的强缓存和协商缓存

    浏览器的强缓存和协商缓存 这里说的缓存是指浏览器(客户端)在本地磁盘中对访问过的资源保存的副本文件. 浏览器缓存主要有以下几个优点: 减少重复数据请求,避免通过网络再次加载资源,节省流量. 降低服务器 ...

  9. 浏览器缓存和vue-cli缓存策略

    缓存的分类: HTTP缓存根据缓存的节点,分为私有缓存和共享缓存. 私有缓存是绑定到特定客户端的缓存--通常是浏览器缓存.由于存储的响应不与其他客户端共享,因此私有缓存可以存储该用户的个性化响应. 共 ...

最新文章

  1. gdoi2017总结
  2. LISP 图层前后缀_lisp获取qleader端点_lisp以一个图层来做定义快名称怎么实现
  3. html5画板功能,JS实现canvas简单小画板功能
  4. 学会用taro封装一个组件
  5. python实现简易工资管理系统(Salary Manage)源码
  6. (4.28)for xml path 在合并拆分上的作用演示
  7. android 分析boot.img,Android 系统准备知识-bootimg文件的结构
  8. tensorflow 根据节点获取节点前的整张图
  9. 围棋人机大战属于计算机在什么方面的应用,《信息技术基础》第一章复习题库...
  10. 互联网日报 | 虎牙与斗鱼官宣合并;国内第四大运营商中国广电成立;拍拍贷完成存量业务清退...
  11. openharmony常用网站
  12. 这些华为技巧,花粉都不一定全知道
  13. 自大型人格分析,如何改变自大型性格?
  14. iOS主线程卡顿监测
  15. 语法长难句-----简单句
  16. java交通信号灯毕业论文范文_信号灯设计论文,关于基于FPGA的交通信号灯控制系统设计相关参考文献资料-免费论文范文...
  17. 芦荟怎么吃 这样吃很美味
  18. Cocos2dx项目移植Android平台
  19. linux rdesktop 远程,linux下rdesktop远程联接windows系统(配合xshell工具的使用及遇到的问题)...
  20. STM32F030 多通道ADC DMA采集

热门文章

  1. 【linux】Valgrind工具集详解(一):简介
  2. 使用svn时碰到的一个的问题
  3. 【转载】linux静态链接库与动态链接库的区别及动态库的创建
  4. java 继承 意义_Java中继承,类的高级概念的知识点
  5. ubuntu mysql emma_Ubuntu 11.10 MySQL客户端 Emma 6.0 中文乱码解决办法
  6. matlab一元线性回归分析_建模开讲:一元线性回归分析及SPSS软件实现
  7. 多个网站共享一个mysql数据库_如何在多个Postgresql数据库之间共享表
  8. mysql金库模式_Python vault-anyconfig包_程序模块 - PyPI - Python中文网
  9. 谷歌浏览器打不开设置等页面
  10. 软件测试--利用组合覆盖法设计测试用例