本文详细介绍了如何从零开始搭建一个Koa服务器来一步一步理解浏览器的缓存机制
本文代码地址:koa-http
建议将代码拉下来之后,配合本文一起查看,效果更佳。
## 搭建本地服务器
1、新建文件夹并进入,命名为:http
mkdir http && cd http
2、初始化 package.json 文件,默认已经安装 node 以及 npm(如需安装 yarn,执行 npm install -g yarn)
yarn init 按照提示填写项目基本信息
3、安装相关依赖
yarn add koa koa-router fs-extra path mime crypto nodemon
4、在 http 目录下创建 src
index.js 入口文件,index.html 首页源代码,source.jpg 和 style.css 是 index.html 用到的图片和样式。
index.html
style.css
index.js
运行代码
yarn start
访问页面如下:
当前服务器没有配置缓存,可以看到size部分显示了资源的大小。如果是命中强缓存就会显示from memory cache或from disk cache
## 强缓存
强缓存是浏览器在本地判定缓存是否有过期,未过期直接从内存和磁盘读取缓存,整个过程不需要和服务器通信,返回的状态码是200。
HTTP 1.0
expires
expires是HTTP1.0中定义的缓存字段,当我们请求一个资源,服务器返回时,可以在Response Headers中增加expires字段表示资源的过期时间。它是一个时间戳,当客户端再次请求该资源的时候,会把客户端时间与该时间戳进行对比,如果大于该时间戳则已过期,否则直接使用该缓存资源。但会有问题,发送请求时是使用客户端时间去对比。一是客户端和服务端时间可能快慢不一致,另一方面是客户端的时间是可以自行修改的(比如浏览器是跟随系统时间的,修改系统时间会影响到),所以不一定满足预期。
修改 src/index.js 中处理图片的路由,在响应头中加上了 expires 字段,过期时间为 2 分钟后。
第一次访问:
2 分钟内再次刷新页面,Status Code 会显示from memory cache
HTTP1.1
cache-control
HTTP1.1新增了cache-control字段来解决HTTP1.0 expires存在的问题,当cache-control和expires都存在时,cache-control优先级更高。
1、响应头添加 cache-control: no-cache,即不允许使用强缓存。
设置了 cache-control: no-cache 后,每次刷新都是下面截图一样,浏览器不再使用缓存,如果使用了缓存Status Code 部分有说明。得出结论 cache-control 确实优先级比 expires 高。
2、设置 cache-control: max-age=60,缓存1分钟后失效。
第一次访问:
1 分钟内再次刷新页面,Status Code 会显示from memory cache
## 协商缓存
协商缓存需要向服务器发送一次协商请求,请求时带上和协商缓存相关的请求头,由服务器判断缓存是否过期,未过期就返回状态码304,浏览器当发现响应的返回码是304就直接读取本地缓存,如果服务器判定过期就直接返回请求资源,状态码为200。
Last-Modified / If-Modified-Since
Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间。
If-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件。
第一次访问:
再次刷新页面,Status Code 为304
Etag / If-None-Match
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。
f-None-Match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。服务器收到该请求后,发现该请求头中含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200。
第一次访问:
再次刷新页面,Status Code 为304
总结
强缓存优先于协商缓存进行,若强缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存。
文章及代码中如有问题,欢迎指正,谢谢!