http缓存 cdn缓存
一、ETag
第一次请求第一次请求时候请求参数中并没有 If-None-Match 字段但是却有个Pragma;同时在请求的Response中有一个 ETag: W/"a-QFZ79AprHeNlMfPMKXyEUV+lyOg"字段。
第二次请求
刷新页面后再次请求在请求头中却有个 If-None-Match: W/"a-QFZ79AprHeNlMfPMKXyEUV+lyOg" ,If-None-Match 的值和第一次请求的ETag的值相同。
也就是说,浏览器会根据HTTP请求的ETag验证请求的资源是否发生了改变,如果它未发生变化,服务器将返回“304 Not Modified”响应,并且资源从浏览器缓存中读取,这样就不必再次下载请求。
为了验证查证的结果,我又添加一个请求处理。这个过程是,客户端明确返回一个ETag, 但是这里每次请求的的返回值都不相同,这里简单的使用了个etag++。
// app.js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('hello http');
})
// 验证ETag
let etag = 0;
app.get('/test', (req, res) => {
etag++;
res.set('ETag', etag);
res.send('ETag');
})
app.listen(3000, () => {
console.log('The server is running at http://127.0.0.1:3000/')
})
查看下 /test 地址的请求结果,会发现If-None-Match 的值和 Response中的 ETag值每次都不相同,并且是 浏览器会将每次的 ETag 值都缓存起来在下次请求的时候发送给服务器。这样一来,每次服务器每次校验的值都是不相同的,所以这种就没有做缓存,因此每次请求 /test 地址都是 200 的状态。
image.png二、Last-Modified
http响应Last-Modified和ETag
http协议 - 浅谈ETag
Etag是在HTTP 1.1中引入的,为了解决一些Last-Modified无法解决的问题,比如:
- 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
- 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)
- 部分服务器不支持精确时间;
为此,HTTP/1.1引入了Etag(Entity Tags).Etag仅仅是一个和文件相关的标记,可以是一个版本标记,比如说v1.0.0或者说"2e681a-6-5d044840"这么一串看起来 很神秘的编码。但是HTTP/1.1 标准并没有规定Etag的内容是什么或者说要怎么实现,唯一规定的是Etag需要放在""内。
ETag和Last-Modified的作用和用法也是差不多,说一说他们的区别。首先在精确度上,Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。第二在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。第三在优先级上,服务器校验优先考虑Etag。
知乎 关于浏览器的缓存,有了Etag
,last-Modified
还有必要存在吗???
三、强缓存和协商缓存
HTTP 缓存机制一二三
一文读懂前端缓存
HTTP 头信息控制缓存大致分为两种:强缓存和协商缓存。强缓存如果命中缓存不需要和服务器端发生交互,而协商缓存不管是否命中都要和服务器端发生交互,强制缓存的优先级高于协商缓存。
1.Expires
这是 HTTP 1.0 的字段,表示缓存到期时间,是一个绝对的时间 (当前时间+缓存时间),如Expires: Thu, 10 Nov 2017 08:45:11 GMT
。在响应消息头中,设置这个字段之后,就可以告诉浏览器,在未过期之前不需要再次请求。但是,这个字段设置时有两个缺点:
- 由于是绝对时间,用户可能会将客户端本地的时间进行修改,而导致浏览器判断缓存失效,重新请求该资源。此外,即使不考虑自行修改,时差或者误差等因素也可能造成客户端与服务端的时间不一致,致使缓存失效。
- 写法太复杂了。表示时间的字符串多个空格,少个字母,都会导致非法属性从而设置失效。
2.Cache-control
已知Expires的缺点之后,在HTTP/1.1中,增加了一个字段Cache-control,该字段表示资源缓存的最大有效时间,在该时间内,客户端不需要向服务器发送请求。这两者的区别就是前者是绝对时间,而后者是相对时间。如下:Cache-control: max-age=2592000
。Cache-control 的优先级高于 Expires,为了兼容 HTTP/1.0 和 HTTP/1.1,实际项目中两个字段我们都会设置。
Cache-Control 可以由多个字段组合而成,主要有以下几个取值:
(1)max-age
指定一个时间长度,在这个时间段内缓存是有效的,单位是s。例如设置 Cache-Control:max-age=31536000,也就是说缓存有效期为(31536000 / 24 / 60 * 60)天,第一次访问这个资源的时候,服务器端也返回了 Expires 字段,并且过期时间是一年后。
(2)s-maxage
同 max-age,覆盖 max-age、Expires,但仅适用于共享缓存,在私有缓存中被忽略。
(3)public
表明响应可以被任何对象(发送请求的客户端、代理服务器等等)缓存。
(4)private
表明响应只能被单个用户(可能是操作系统用户、浏览器用户)缓存,是非共享的,不能被代理服务器缓存。
(5)no-cache
强制所有缓存了该响应的用户,在使用已缓存的数据前,发送带验证器的请求到服务器。不是字面意思上的不缓存。
(6)no-store
禁止缓存,每次请求都要向服务器重新获取数据。
(7)must-revalidate
如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效。
这里有一个疑问:max-age=0 和 no-cache 等价吗?从规范的字面意思来说,max-age 到期是 应该(SHOULD) 重新验证,而 no-cache 是 必须(MUST) 重新验证。但实际情况以浏览器实现为准,大部分情况他们俩的行为还是一致的。(如果是 max-age=0, must-revalidate 就和 no-cache 等价了)
顺带一提,在 HTTP/1.1 之前,如果想使用 no-cache,通常是使用 Pragma 字段,如 Pragma: no-cache(这也是 Pragma 字段唯一的取值)。但是这个字段只是浏览器约定俗成的实现,并没有确切规范,因此缺乏可靠性。它应该只作为一个兼容字段出现,在当前的网络环境下其实用处已经很小。
四、HTTP 缓存实际应用
1.首先要明确哪些内容适合被缓存哪些不适合
考虑缓存的内容:
- css样式文件
- js文件
- logo、图标
- html文件
- 可以下载的内容
一些不应该被缓存的内容:
- 业务敏感的 GET 请求
2.可缓存的内容又分为几种不同的情况
(1)不经常改变的文件
给 max-age 设置一个较大的值,一般设置 max-age=31536000
比如引入的一些第三方文件、打包出来的带有 hash 后缀 css、js 文件。一般来说文件内容改变了,会更新版本号、hash 值,相当于请求另一个文件。
标准中规定 max-age 的值最大不超过一年,所以设成 max-age=31536000。至于过期内容,缓存区会将一段时间没有使用的文件删除掉。
(2)可能经常需要变动的文件:
Cache-Control: no-cache / max-age=0
比如入口 index.html 文件、文件内容改变但名称不变的资源。选择 ETag 或 Last-Modified 来做验证,在使用缓存资源之前一定会去服务器端做验证,命中缓存时会比第一种情况慢一点点,毕竟还要发请求进行通信。
五、cdn缓存
http缓存与cdn缓存配置指南
闲话 CDN
从HTTP响应头看各家CDN缓存技术
【CDN学习笔记1】CDN基本概念和原理
【CDN学习笔记2】如何判断CDN缓存是否生效
【CDN学习笔记3】CDN缓存规则错误导致网页显示错误和预热失败的案例
【CDN学习笔记4】CDN缓存刷新与预热的区别
【CDN学习笔记5】源站IP变更后导致图片显示不出来的案例
【CDN学习笔记6】CDN回源到阿里云主机被拒绝的案例
【CDN学习笔记7】CDN几种常见的组网方式
Web 缓存大致可以分为:数据库缓存、服务器端缓存(代理服务器缓存、CDN 缓存)、浏览器缓存。浏览器缓存也包含很多内容: HTTP 缓存、indexDB、cookie、localstorage 等等。
cdn缓存是一种服务端缓存,CDN服务商将源站的资源缓存到遍布全国的高性能加速节点上,当用户访问相应的业务资源时,用户会被调度至最接近的节点最近的节点ip返回给用户,在web性能优化中,它主要起到了,缓解源站压力,优化不同用户的访问速度与体验的作用。
1.流程
image.png客户端访问网站的过程:没有CDN:
- 用户在浏览器访问栏中输入要访问的域名;
- 浏览器向DNS服务器请求对该域名的解析;
- DNS服务器返回该域名的IP地址给浏览器
- 浏览器使用该IP地址向服务器请求内容。
- 服务器将用户请求的内容返回给浏览器。
使用了CDN:
- 用户在浏览器中输入要访问的域名。
- 浏览器向DNS服务器请求对域名进行解析。由于CDN对域名解析进行了调整,DNS服务器会最终将域名的解析权交给CNAME指向的CDN专用DNS服务器。
- CDN的DNS服务器将CDN的负载均衡设备IP地址返回给用户。
- 用户向CDN的负载均衡设备发起内容URL访问请求。
- CDN负载均衡设备会为用户选择一台合适的缓存服务器提供服务。选择的依据包括:根据用户IP地址,判断哪一台服务器距离用户最近;根据用户所请求的URL中携带的内容名称,判断哪一台服务器上有用户所需内容;查询各个服务器的负载情况,判断哪一台服务器的负载较小。基于以上这些依据的综合分析之后,负载均衡设置会把缓存服务器的IP地址返回给用户。
- 用户向缓存服务器发出请求。
- 缓存服务器响应用户请求,将用户所需内容传送到用户。如果这台缓存服务器上并没有用户想要的内容,而负载均衡设备依然将它分配给了用户,那么这台服务器就要向它的上一级缓存服务器请求内容,直至追溯到网站的源服务器将内容拉取到本地。
2.缓存规则
在用户第一次访问网站后,网站的一些静态资源如图片等就会被下载到本地,作为缓存,当用户第二次访问该网站的时候,浏览器就会从缓存中加载资源,不用向服务器请求资源,从而提高了网站的访问速度,而若使用了CDN,当浏览器本地缓存的资源过期之后,浏览器不是直接向源站点请求资源,而是向CDN边缘节点请求资源,CDN边缘节点中也存在缓存,若CDN中的缓存也过期,那就由CDN边缘节点向源站点发出回源请求来获取最新资源。
CDN节点缓存机制在不同服务商中是不同的,但一般都遵循HTTP协议,通过http响应头中的Cache-Control:max-age的字段来设置CDN节点文件缓存时间。当客户端向CDN节点请求数据时,CDN会判断缓存数据是否过期,若没有过期,则直接将缓存数据返回给客户端,否则就向源站点发出请求,从源站点拉取最新数据,更新本地缓存,并将最新数据返回给客户端。CDN服务商一般会提供基于文件后缀、目录多个维度来指定CDN缓存时间,为用户提供更精细化的缓存管理。CDN缓存时间会对“回源率”产生直接的影响,若CDN缓存时间短,则数据经常失效,导致频繁回源,增加了源站的负载,同时也增大了访问延时;若缓存时间长,数据更新时间慢,因此需要针对不同的业务需求来选择特定的数据缓存管理。
以腾讯云举例,打开cdn加速服务配置,面板如下。
image.png
可以看到,提供给我们的配置项只有文件类型(或文件目录)和刷新时间,意义也很简单,针对不同文件类型,在cdn节点上缓存对应的时间。
六、推荐阅读 知乎 大公司里怎样开发和部署前端代码?
大公司的静态资源优化方案,基本上要实现这么几个东西:
- 配置超长时间的本地缓存 —— 节省带宽,提高性能
- 采用内容摘要作为缓存更新依据 —— 精确的缓存控制
- 静态资源CDN部署 —— 优化网络请求
- 更资源发布路径实现非覆盖式发布 —— 平滑升级