下文以Chrome浏览器和nodeJs举例。
查看浏览器缓存需要下载一个工具ChromeCacheView:
http://www.nirsoft.net/utils/chrome_cache_view.html
HTTP/1.1定义的Cache-Control用来区分对缓存机制的支持情况,请求头和响应头均可以使用该字段。该字段有很多指令和参数,参见: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Directives
no-cache指令可以来自服务器也可以来自客户端,使用no-cache指令的目的是为了防止从缓存中返回过期的资源。
客户端发送的请求中如果包含no-cache指令,则表示客户端将不会接收缓存过的响应,于是中间的缓存服务器需要将来自客户端的请求转发给源服务器。
服务器返回的响应中如果包含no-cache指令,那么缓存服务器不能对资源进行缓存。源服务器以后也将不再对缓存服务器请求中提出的资源有效性进行确认,且禁止其对响应资源进行缓存操作。
Cache-Control:no-cache
如上定义,每次有请求发出时,缓存会将此请求发到源服务器,源服务器端会验证请求中所描述的缓存是否过期,若未过期(实际就是返回304),则缓存才使用本地缓存副本。
该指令规定缓存不能在本地存储请求或响应的任一部分。
需要注意的是:no-cache不是不缓存,而是不缓存过期的资源,缓存会向源服务器进行有效性确认后再处理资源。no-store才是真正的不缓存资源。
Cache-Control:no-store
主要是max-age指令,该指令的参数是一个整数,单位为秒,表示资源能够被缓存(保持新鲜)的最大时间。相对Expires而言,max-age是距离请求发起的时间的秒数。
Cache-Control:max-age=3600
Null
如上定义,表示请求资源将被缓存3600秒。
Cache-Control:must-revalidate
如上定义,当使用了must-revalidate指令,那就意味着缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用。
const http = require("http");
const fs = require("fs");
http.createServer(function(req,res){
if(req.url === "/"){
const readStream = fs.createReadStream("./index.html");
res.setHeader("Content-Type","text/html");
readStream.pipe(res);
}else if(req.url === "/loadString"){
const readStream = fs.createReadStream("./text.txt");
res.setHeader("Content-Type","text/plain");
readStream.pipe(res);
}else{
res.statusCode = 404;
res.end()
}
}).listen(4000);
使用强缓存,最简单的办法就是响应头设置max-age:
res.setHeader("Cache-Control","max-age=20");
该资源将被缓存20秒。
解决这2个问题需要用到:协商缓存。
协商缓存需要用到2个字段: * 响应头的Last-Modified字段 * 请求头的If-Modified-Since字段
其参数值为UTC时间字符串。
const mtime = fs.statSync("./text.txt").mtime.toUTCString();
if(req.headers["if-modified-since"] === mtime){
res.writeHead(304,"Not Modified",{
"Cache-Control":"max-age=5",
"Last-Modified":mtime
});
res.end();
}else{
res.writeHead(200,"Ok",{
"Cache-Control":"max-age=5",
"Last-Modified":mtime
});
readStream.pipe(res);
}
fs模块的statSync方法用于同步获取一个文件的时间,mtime属性表示其修改时间。
上例是强缓存+协商缓存的方式。
如何一直使用协商缓存呢?只需要将:
"Cache-Control":"max-age=5"
修改为:
"Cache-Control":"no-cache",
注意:no-store不可以实现协商缓存。
协商缓存的Last-Modified可能会存在一些问题: * 某些服务端没有办法获取精确的修改时间,导致last-modified有问题 * 文件时间修改了,但文件内容却没有变
所以,通常还会用到另一个首部字段:ETag
该字段属于响应首部字段,能告知客户端资源实体标记,将资源以字符串形式做唯一标识,服务器为每份新资源分配对应的ETag值,ETag的生成并没有统一的算法规则。
该字段属于请求首部字段,与ETag对应,二者的关系类似If-Not-Modified与Last-Modified。
通常的服务端处理流程:
1. 首先判断请求头的etag
字段与对应请求资源本身的ETag
是否相等
2. 如果相等,走第5步
3. 如果不相等,则继续判断请求头的If-Not-Modified
与对应资源的Last-Modified
是否相等
4. 如果相等,走第5步
5. 响应304,结束请求
6. 否则,读取实体资源返回
res.setHeader("Last-Modified":"Tue, 13 Aug 2019 12:02:47 GMT")
,读取为:req.headers["if-not-modified"]
End~
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。