We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
本系列的主题是浏览器,每期讲解一个技术要点。如果你还不了解各系列内容,文末点击查看全部文章,点我跳转到文末。
如果觉得本系列不错,欢迎 Star,你的支持是我创作分享的最大动力。
缓存:保存资源副本并在下次请求时直接使用该副本。
HTTP 缓存分为 2 种,一种是强缓存,另一种是协商缓存。
缓存的主要作用是可以加快资源获取速度,提升用户体验,减少网络传输,缓解服务端的压力。。
强缓存就是不需要发送请求到服务端,直接读取浏览器本地缓存,在 Chrome 的 Network 中显示的 HTTP 状态码是 200 。
在 Chrome 中,强缓存又分为 Disk Cache (存放在硬盘中)和 Memory Cache (存放在内存中),存放的位置是由浏览器控制的。是否强缓存由 Expires、Cache-Control 和 Pragma 3 个 Header 属性共同来控制。
Expires 的值是一个 HTTP 日期,在浏览器发起请求时,会根据系统时间和 Expires 的值进行比较,如果系统时间超过了 Expires 的值,缓存失效。由于和系统时间进行比较,所以当系统时间和服务器时间不一致的时候,会有缓存有效期不准的问题。Expires 的优先级在三个 Header 属性中是最低的。
Expires
Cache-Control 是 HTTP/1.1 中新增的属性,在请求头和响应头中都可以使用,常用的属性值如有:
Cache-Control
Pragma 只有一个属性值,就是 no-cache ,效果和 Cache-Control 中的 no-cache 一致,不使用强缓存,需要与服务器验证缓存是否新鲜,在 3 个头部属性中的优先级最高。
Pragma
no-cache
本地通过 express 起一个服务来验证强缓存的 3 个属性,代码如下:
express
const express = require('express'); const app = express(); var options = { etag: false, // 禁用协商缓存 lastModified: false, // 禁用协商缓存 setHeaders: (res, path, stat) => { res.set('Cache-Control', 'max-age=10'); // 强缓存超时时间为10秒 }, }; app.use(express.static((__dirname + '/public'), options)); app.listen(3000);
第一次加载,页面会向服务器请求数据,并在 Response Header 中添加 Cache-Control ,过期时间为 10 秒。
Response Header
第二次加载,Date 头属性未更新,可以看到浏览器直接使用了强缓存,实际没有发送请求。
过了 10 秒的超时时间之后,再次请求资源:
当 Pragma 和 Cache-Control 同时存在的时候,Pragma 的优先级高于 Cache-Control。
协商缓存是一种服务端的缓存策略,即通过服务端来判断某件请求是否可以命中缓存。
服务端判断客户端的资源,是否和服务端资源一样,如果一致则返回 304 ,反之返回 200 和最新的资源。
当浏览器的强缓存失效的时候或者请求头中设置了不走强缓存,并且在请求头中设置了If-Modified-Since 或者 If-None-Match 的时候,会将这两个属性值到服务端去验证是否命中协商缓存,如果命中了协商缓存,会返回 304 状态,加载浏览器缓存,并且响应头会设置 Last-Modified 或者 ETag 属性。
If-Modified-Since
If-None-Match
Last-Modified
ETag
ETag / If-None-Match 的值是一串 hash 码,代表的是一个资源的标识符,当服务端的文件变化的时候,它的 hash码会随之改变,通过请求头中的 If-None-Match 和当前文件的 hash 值进行比较,如果相等则表示命中协商缓存。ETag 又有强弱校验之分,如果 hash 码是以 "W/" 开头的一串字符串,说明此时协商缓存的校验是弱校验的,只有服务器上的文件差异(根据 ETag 计算方式来决定)达到能够触发 hash 值后缀变化的时候,才会真正地请求资源,否则返回 304 并加载浏览器缓存。
Last-Modified / If-Modified-Since 的值代表的是文件的最后修改时间,第一次请求服务端会把资源的最后修改时间放到 Last-Modified 响应头中,第二次发起请求的时候,请求头会带上上一次响应头中的 Last-Modified 的时间,并放到 If-Modified-Since 请求头属性中,服务端根据文件最后一次修改时间和 If-Modified-Since 的值进行比较,如果相等,返回 304 ,并加载浏览器缓存。
本地通过 express 起一个服务来验证协商缓存,代码如下:
const express = require('express'); const app = express(); var options = { etag: true, // 开启协商缓存 lastModified: true, // 开启协商缓存 setHeaders: (res, path, stat) => { res.set({ 'Cache-Control': 'max-age=00', // 浏览器不走强缓存 'Pragma': 'no-cache', // 浏览器不走强缓存 }); }, }; app.use(express.static((__dirname + '/public'), options)); app.listen(3001);
第一次请求资源:
第二次请求资源,服务端根据请求头中的 If-Modified-Since 和 If-None-Match 验证文件是否修改。
ETag / If-None-Match 的出现主要解决了 Last-Modified / If-Modified-Since 所解决不了的问题
Etag
即:
如果看完前面的文章后对HTTP 强缓存和协商缓存 还不是特别理解,可以继续看下面的文章,或许能帮到你;
HTTP 强缓存和协商缓存
如果前面的文章已经帮你理解了 HTTP 强缓存和协商缓存,则可以略过下面的文章。
强缓存
先看第一个图:
从上图可以看到,当初次请求时,浏览器会向服务器发起请求,服务器接收到浏览器的请求后,返回资源并返回一个 Cache-Control 给客户端,该 Cache-Control 一般设置缓存的最大过期时间。
接下来看第二个图:
从上图中可以看到,此时浏览器已经接收到 cache-control 的值,那么这个时候浏览器再次发送请求时,它会先检查它的 cache-control 是否过期,如果没有过期则直接从本地缓存中拉取资源,返回到客户端,而无需再经过服务器。
cache-control
接下来看第三个图:
强制缓存有过期时间,那么就意味着总有一天缓存会失效。那么假设某一天,客户端的 cache-control 失效了,那么它就没办法从本地缓存中拉取资源。于是它会像第一张图一样,重新向服务器发起请求,之后服务器会再次返回资源和 cache-control 的值。 以上就是强制缓存的全过程。
协商缓存
先来看第一张图:
在上图中,表明了协商缓存的全过程。首先,如果客户端是第一次向服务器发出请求,则服务器返回资源和相对应的资源标识给浏览器。该资源标识就是对当前所返回资源的一种唯一标识,可以是Etag或者是Last-Modified,这两个字段将在图例结束后展开讲解。
之后如果浏览器再次发送请求时,浏览器就会带上这个资源标识。此时,服务端就会通过这个资源标识,可以判断出浏览器的资源跟服务端此时的资源是否一致,如果一致,则返回304,即表示Not Found 资源未修改。如果判断结果为不一致,则返回200,并返回资源以及新的资源标识。至此就结束了协商缓存的过程。
接下来看第二张图:
假设此时我们的协商缓存用 Last-Modified 来判断。当浏览器第一次发送请求时,服务器返回资源并返回一个 Last-Modified 的值给浏览器。这个 Last-Modified 的值给到浏览器之后,浏览器会通过 If-Modified-Since 的字段来保存 Last-Modified 的值,且 If-Modified-Since 保存在请求头当中。
之后当浏览器再次发送请求时,请求头会带着 If-Modified-Since 的值去找服务器,服务器此刻就会匹配浏览器发过来的 If-Modified-Since 是否和自己最后一次修改的 Last-Modified 的值相等。如果相等,则返回 304 ,表示资源未被修改;如果不相等,则返回200,并返回资源和新的 Last-Modified 的值。
接下来看第三张图:
假设此时我们的协商缓存用 Etag 来判断。当浏览器第一次发送请求时,服务器返回资源并返回一个 Etag 的值给浏览器。这个 Etag 的值给到浏览器之后,浏览器会通过 If-None-Match 的字段来保存 Etag 的值,且 If-None-Match 保存在请求头当中。
之后当浏览器再次发送请求时,请求头会带着 If-None-Match 的值去找服务器,服务器此刻就会匹配浏览器发过来的 If-None-Match 是否和自己最后一次修改的 Etag 的值相等。如果相等,则返回 304 ,表示资源未被修改;如果不相等,则返回 200 ,并返回资源和新的 Etag 的值。
查看原文
查看全部文章
各系列文章汇总:https://github.com/yuanyuanbyte/Blog
我是圆圆,一名深耕于前端开发的攻城狮。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
本系列的主题是浏览器,每期讲解一个技术要点。如果你还不了解各系列内容,文末点击查看全部文章,点我跳转到文末。
如果觉得本系列不错,欢迎 Star,你的支持是我创作分享的最大动力。
分析 304 状态码过程,图解 HTTP 强缓存和协商缓存
什么是缓存
缓存:保存资源副本并在下次请求时直接使用该副本。
HTTP 缓存分为 2 种,一种是强缓存,另一种是协商缓存。
为什么需要缓存?
缓存的主要作用是可以加快资源获取速度,提升用户体验,减少网络传输,缓解服务端的压力。。
强缓存
强缓存就是不需要发送请求到服务端,直接读取浏览器本地缓存,在 Chrome 的 Network 中显示的 HTTP 状态码是 200 。
在 Chrome 中,强缓存又分为 Disk Cache (存放在硬盘中)和 Memory Cache (存放在内存中),存放的位置是由浏览器控制的。是否强缓存由 Expires、Cache-Control 和 Pragma 3 个 Header 属性共同来控制。
Expires
Expires
的值是一个 HTTP 日期,在浏览器发起请求时,会根据系统时间和Expires
的值进行比较,如果系统时间超过了Expires
的值,缓存失效。由于和系统时间进行比较,所以当系统时间和服务器时间不一致的时候,会有缓存有效期不准的问题。Expires
的优先级在三个 Header 属性中是最低的。Cache-Control
Cache-Control
是 HTTP/1.1 中新增的属性,在请求头和响应头中都可以使用,常用的属性值如有:Pragma
Pragma
只有一个属性值,就是no-cache
,效果和Cache-Control
中的no-cache
一致,不使用强缓存,需要与服务器验证缓存是否新鲜,在 3 个头部属性中的优先级最高。本地通过
express
起一个服务来验证强缓存的 3 个属性,代码如下:第一次加载,页面会向服务器请求数据,并在
Response Header
中添加Cache-Control
,过期时间为 10 秒。第二次加载,Date 头属性未更新,可以看到浏览器直接使用了强缓存,实际没有发送请求。
过了 10 秒的超时时间之后,再次请求资源:
当
Pragma
和Cache-Control
同时存在的时候,Pragma
的优先级高于Cache-Control
。协商缓存
协商缓存是一种服务端的缓存策略,即通过服务端来判断某件请求是否可以命中缓存。
服务端判断客户端的资源,是否和服务端资源一样,如果一致则返回 304 ,反之返回 200 和最新的资源。
当浏览器的强缓存失效的时候或者请求头中设置了不走强缓存,并且在请求头中设置了
If-Modified-Since
或者If-None-Match
的时候,会将这两个属性值到服务端去验证是否命中协商缓存,如果命中了协商缓存,会返回 304 状态,加载浏览器缓存,并且响应头会设置Last-Modified
或者ETag
属性。ETag/If-None-Match
ETag
/If-None-Match
的值是一串 hash 码,代表的是一个资源的标识符,当服务端的文件变化的时候,它的 hash码会随之改变,通过请求头中的If-None-Match
和当前文件的 hash 值进行比较,如果相等则表示命中协商缓存。ETag
又有强弱校验之分,如果 hash 码是以 "W/" 开头的一串字符串,说明此时协商缓存的校验是弱校验的,只有服务器上的文件差异(根据 ETag 计算方式来决定)达到能够触发 hash 值后缀变化的时候,才会真正地请求资源,否则返回 304 并加载浏览器缓存。Last-Modified/If-Modified-Since
Last-Modified
/If-Modified-Since
的值代表的是文件的最后修改时间,第一次请求服务端会把资源的最后修改时间放到Last-Modified
响应头中,第二次发起请求的时候,请求头会带上上一次响应头中的Last-Modified
的时间,并放到If-Modified-Since
请求头属性中,服务端根据文件最后一次修改时间和If-Modified-Since
的值进行比较,如果相等,返回 304 ,并加载浏览器缓存。本地通过 express 起一个服务来验证协商缓存,代码如下:
第一次请求资源:
第二次请求资源,服务端根据请求头中的
If-Modified-Since
和If-None-Match
验证文件是否修改。ETag
/If-None-Match
的出现主要解决了Last-Modified
/If-Modified-Since
所解决不了的问题Last-Modified
和Etag
的值时,会优先使用Etag
;Last-Modified
只能精确到秒级;Etag
更精确即:
Last-Modified
/If-Modified-Since
会错误地返回 304Last-Modified
/If-Modified-Since
会错误地返回200 并返回资源强缓存
先看第一个图:
从上图可以看到,当初次请求时,浏览器会向服务器发起请求,服务器接收到浏览器的请求后,返回资源并返回一个
Cache-Control
给客户端,该Cache-Control
一般设置缓存的最大过期时间。接下来看第二个图:
从上图中可以看到,此时浏览器已经接收到
cache-control
的值,那么这个时候浏览器再次发送请求时,它会先检查它的cache-control
是否过期,如果没有过期则直接从本地缓存中拉取资源,返回到客户端,而无需再经过服务器。接下来看第三个图:
强制缓存有过期时间,那么就意味着总有一天缓存会失效。那么假设某一天,客户端的 cache-control 失效了,那么它就没办法从本地缓存中拉取资源。于是它会像第一张图一样,重新向服务器发起请求,之后服务器会再次返回资源和
cache-control
的值。以上就是强制缓存的全过程。
协商缓存
先来看第一张图:
在上图中,表明了协商缓存的全过程。首先,如果客户端是第一次向服务器发出请求,则服务器返回资源和相对应的资源标识给浏览器。该资源标识就是对当前所返回资源的一种唯一标识,可以是
Etag
或者是Last-Modified
,这两个字段将在图例结束后展开讲解。之后如果浏览器再次发送请求时,浏览器就会带上这个资源标识。此时,服务端就会通过这个资源标识,可以判断出浏览器的资源跟服务端此时的资源是否一致,如果一致,则返回304,即表示Not Found 资源未修改。如果判断结果为不一致,则返回200,并返回资源以及新的资源标识。至此就结束了协商缓存的过程。
接下来看第二张图:
假设此时我们的协商缓存用
Last-Modified
来判断。当浏览器第一次发送请求时,服务器返回资源并返回一个Last-Modified
的值给浏览器。这个Last-Modified
的值给到浏览器之后,浏览器会通过If-Modified-Since
的字段来保存Last-Modified
的值,且If-Modified-Since
保存在请求头当中。之后当浏览器再次发送请求时,请求头会带着
If-Modified-Since
的值去找服务器,服务器此刻就会匹配浏览器发过来的If-Modified-Since
是否和自己最后一次修改的Last-Modified
的值相等。如果相等,则返回 304 ,表示资源未被修改;如果不相等,则返回200,并返回资源和新的 Last-Modified 的值。接下来看第三张图:
假设此时我们的协商缓存用
Etag
来判断。当浏览器第一次发送请求时,服务器返回资源并返回一个Etag
的值给浏览器。这个Etag
的值给到浏览器之后,浏览器会通过If-None-Match
的字段来保存Etag
的值,且If-None-Match
保存在请求头当中。之后当浏览器再次发送请求时,请求头会带着
If-None-Match
的值去找服务器,服务器此刻就会匹配浏览器发过来的If-None-Match
是否和自己最后一次修改的Etag
的值相等。如果相等,则返回 304 ,表示资源未被修改;如果不相等,则返回 200 ,并返回资源和新的Etag
的值。参考
查看原文
查看全部文章
博文系列目录
交流
各系列文章汇总:https://github.com/yuanyuanbyte/Blog
我是圆圆,一名深耕于前端开发的攻城狮。
The text was updated successfully, but these errors were encountered: