摘要:概念缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。缓存能缓解服务器压力,提高响应速度,提升用户体验。以下讨论的缓存是针对对资源而言的,且缓存策略都是依靠报文的首部来实现。参考缓存控制小结浅谈浏览器的缓存机制
概念
缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。——MDN
缓存能缓解服务器压力,提高响应速度,提升用户体验。
以下讨论的缓存是针对对img/script/css资源而言的,且缓存策略都是依靠 http 报文的首部来实现。
实验 搭建实验环境编写 html 文件
缓存 缓存实验
服务端代码
const path = require("path") const url = require("url") const fs = require("fs") const zlib = require("zlib") const img = fs.readFileSync(path.resolve(__dirname, "./static/sun.jpg"), "binary") http.createServer((req, res) => { const html = fs.createReadStream(path.resolve(__dirname, "./static/index.html")) let { pathname } = url.parse(req.url) if (pathname === "/") { res.writeHead(200, { "Content-Type": "text/html", "Content-Encoding": "gzip" }) html.pipe(zlib.createGzip()).pipe(res) } else if (pathname === "/sun.jpg") { res.writeHead(200, { "Content-Type": "image/jpeg" }) res.write(img, "binary") res.end() } else { res.end(pathname) } }).listen(3210)
访问 http://localhost:3210 , 看到相应的文档和图片,且无论刷新多少次,sun.jpg 的 Status 和 Size 都不变。控制台里勾选 Preserve log
Cache-Control通过在服务端设置相应首部 Cache-Control 可以控制缓存行为,例如
Cache-Control: no-cache, 告诉浏览器,下次请求该资源时,不直接使用缓存,而是向服务端发送请求,服务端会根据请求,判断本地的资源是否过期
Cache-Control: no-store, 告诉浏览器,不要缓存该资源
Cache-Control: max-age=age, 告诉浏览器,这个资源有效的时长 age,在该时间范围内,如果需要该资源,直接从本地取,不要烦我(向我发送请求)
修改服务端代码设置图片缓存时长 30s
res.writeHead(200, { "Content-Type": "image/jpeg", "Cache-Control": "max-age=30" })
快速刷新页面2次,超过30s后,再刷新一次
三次刷新结果在控制台显示的情况如下
其中第二次请求 sun.jpg 的请求情况如下,200 OK (from memory cache),第三次请求 sun.jpg 则又是从服务端获取图片,显示资源 1.6M。
现在的情形是这样的,30s到了,浏览器向服务端发出 sun.jpg 的请求,但服务器并没有更新该资源,所以服务器告诉浏览器,“我没有修改该资源,你还是用你本地的吧,我就不再发给你了”。这些通过 Last-Modified 和 If-Modified-Since 来实现。
浏览器第一次向服务端请求 sun.jpg,服务端不仅返回 sun.jpg,还通过响应首部的 Last-Modified(浏览器自动添加),告诉浏览器该资源最后修改的时间。
下次浏览器再次请求 sun.jpg,会通过请求首部的 If-Modified-Since, 把自己手上这个资源最后修改的时间告诉服务端,服务端通过这个时间,判断浏览器本地的资源是否是最新的,若是,则返回 304(not modified) 和响应头部即可,不用返回图片;若不是,则返回 200 和图片。
修改服务端代码const http = require("http") const path = require("path") const url = require("url") const fs = require("fs") const zlib = require("zlib") const img = fs.readFileSync(path.resolve(__dirname, "./static/sun.jpg"), "binary") let date = new Date() let lastModified = date.toUTCString() http.createServer((req, res) => { const html = fs.createReadStream(path.resolve(__dirname, "./static/index.html")) let { pathname } = url.parse(req.url) if (pathname === "/") { res.writeHead(200, { "Content-Type": "text/html", "Content-Encoding": "gzip" }) html.pipe(zlib.createGzip()).pipe(res) } else if (pathname === "/sun.jpg") { if (req.headers["if-modified-since"] === lastModified) { res.writeHead(304, { "Content-Type": "image/jpeg", "Cache-Control": "max-age=30", "Last-Modified": lastModified }) res.end() } else { res.writeHead(200, { "Content-Type": "image/jpeg", "Cache-Control": "max-age=30", "Last-Modified": lastModified }) res.write(img, "binary") res.end() } } else { res.end(pathname) } }).listen(3210)
浏览器刷新一次,30s内,再刷新一次,30s后再刷新一次
三次刷新的结果在控制台里显示如下,最后一次还有 189B 是服务端响应头部的大小,178ms 里包含了服务端比较修改时间,返回响应头部的时间。
且最后一次请求 sun.jpg 的请求情形如下
ETag & If-None-MatchEtag 和 If-None-Match 起到的作用和上文中 Last-Modified 和 If-Modified 差不多,区别在于 Etag 是服务端上通过算法给资源计算出的唯一标示,当资源修改时,该标示会发生变化。服务端通过响应首部 Etag 将该标示告诉浏览器,浏览器再下一次请求该资源时,会通过请求首部 If-None-Match 带上该标示,服务端会比较请求中的标示和该资源最新的标示,如果一样,证明浏览器拥有的该资源是最新的,仅返回304和响应头部,否则返回200和整个资源。
强制刷新常使用的强制刷新就是通过修改请求首部来实现的
将 Cache-Control 和 Pragma 设为 no-cache,去除 If-Modified, If-None-Match
盗个图,HTTP缓存控制小结 快速更新很多js文件或css文件的文件名会带有文件指纹或版本号,通过改变文件名,让浏览器以为请求的新的未缓存的资源从而实现快速更新。
参考HTTP缓存控制小结
[浅谈浏览器http的缓存机制](http://www.cnblogs.com/vajoy/...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/92163.html
摘要:服务器告诉客户,原来缓冲的文档还可以继续使用。不是服务器发出的错误提示。如果相同,则获取本地的缓存信息,反之服务器返回新的资源。服务器静态资源修改了,返回的,也会修改这个是乐视网首页第二次请求时的截包,会发现静态资源的返回基本都是 http 304 好久没写了。感觉荒废了好久。刚好今天有朋友问我关于静态资源缓存问题。突然唤起我的学习兴趣了。发现好多同学对静态资源都不是很清楚。小弟我刚好...
摘要:服务器告诉客户,原来缓冲的文档还可以继续使用。不是服务器发出的错误提示。如果相同,则获取本地的缓存信息,反之服务器返回新的资源。服务器静态资源修改了,返回的,也会修改这个是乐视网首页第二次请求时的截包,会发现静态资源的返回基本都是 http 304 好久没写了。感觉荒废了好久。刚好今天有朋友问我关于静态资源缓存问题。突然唤起我的学习兴趣了。发现好多同学对静态资源都不是很清楚。小弟我刚好...
摘要:可以发送通知消息以再次吸引用户并留住他们。在即时通讯等使用情形中,一条消息可将最多的有效负载传送至客户端应用。浏览器的的消息推送主要依赖,服务端消息推送传递到,然后再由推送到客户端。 引言 Progressive Web App, 简称 PWA,是提升 Web App 的体验的一种新方法,能给用户原生应用的体验。Service Worker 是 PWA 中的重要一部分。Service ...
阅读 1915·2021-11-23 10:03
阅读 4016·2021-11-22 09:34
阅读 2396·2021-10-08 10:05
阅读 2193·2019-08-30 15:53
阅读 1651·2019-08-30 13:56
阅读 1119·2019-08-29 16:52
阅读 1053·2019-08-26 13:31
阅读 3322·2019-08-26 11:45