浏览器缓存方式分为哪些?

浏览器缓存分为强缓存和协商缓存。当客户端请求某个资源时,获取缓存的流程如下

  • 先根据这个资源的一些 http header 判断它是否命中强缓存,如果命中,则直接从本地获取缓存资源,不会发请求到服务器;

  • 当强缓存没有命中时,客户端会发送请求到服务器,服务器通过另一些 request header 验证这个资源是否命中协商缓存,称为 http 再验证,如果命中,服务器将请求返回,但不返回资源,而是告诉客户端直接从缓存中获取,客户端收到返回后就会从缓存中获取资源;

  • 强缓存和协商缓存共同之处在于,如果命中缓存,服务器都不会返回资源; 区别是,强缓存不对发送请求到服务器,但协商缓存会。

  • 当协商缓存也没命中时,服务器就会将资源发送回客户端。

  • 当 ctrl+f5 强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存;

  • 当 f5 刷新网页时,跳过强缓存,但是会检查协商缓存;

在这里插入图片描述

强缓存

  • Expires(该字段是 http1.0 时的规范,值为一个绝对时间的 GMT 格式的时间字符串,代表缓存资源的过期时间)

  • Cache-Control:max-age(该字段是 http1.1的规范,强缓存利用其 max-age 值来判断缓存资源的最大生命周期,它的值单位为秒)

const http = require('http');
const fs = require('fs');
const path = require('path');

http.createServer((req, res) => {
	const filePath = path.join(__dirname, 'public', req.url);
	fs.readFile(filePath, (err, data) => {
		if (err) {
			res.writeHead(404);
			res.end('File not found');
			return;
		}
		const stat = fs.statSync(filePath);
		const expires = new Date(Date.now() + 3600000); // 设置缓存过期时间为1小时
		res.setHeader('Expires', expires.toUTCString());
		res.setHeader('Cache-Control', 'max-age=3600');
		res.writeHead(200);
		res.end(data);
	});
}).listen(3000, () => {
	console.log('Server is running on port 3000');
});

协商缓存

  • Last-Modified(值为资源最后更新时间,随服务器response返回)

  • If-Modified-Since(通过比较两个时间来判断资源在两次请求期间是否有过修改,如果没有修改,则命中协商缓存)

  • ETag(表示资源内容的唯一标识,随服务器response返回)

  • If-None-Match(服务器通过比较请求头部的If-None-Match与当前资源的ETag是否一致来判断资源是否在两次请求之间有过修改,如果没有修改,则命中协商缓存)

const http = require('http');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

http.createServer((req, res) => {
	const filePath = path.join(__dirname, 'public', req.url);
	fs.readFile(filePath, (err, data) => {
		if (err) {
			res.writeHead(404);
			res.end('File not found');
			return;
		}

		const stat = fs.statSync(filePath);
		const lastModified = stat.mtime.toUTCString();
		const ifModifiedSince = req.headers['if-modified-since'];
		const fileHash = crypto.createHash('md5').update(data).digest('hex');
		const etag = `"${fileHash}"`;
		const ifNoneMatch = req.headers['if-none-match'];
		
		if (ifModifiedSince && lastModified === ifModifiedSince) {
			res.writeHead(304); // 文件未修改,返回 304 Not Modified
			res.end();
		} else if (ifNoneMatch && etag === ifNoneMatch) {
			res.writeHead(304); // 文件未修改,返回 304 Not Modified
			res.end();
		} else {
			res.setHeader('Last-Modified', lastModified);
			res.setHeader('ETag', etag);
			res.writeHead(200);
			res.end(data);
		}
	});
}).listen(3000, () => {
	console.log('Server is running on port 3000');
});

在上述示例中,使用了 crypto 模块计算文件的 MD5 哈希值作为 ETag。在每个请求中,首先检查 If-Modified-Since 请求头和文件的最后修改时间,如果相同则返回 304 Not Modified。然后,检查 If-None-Match 请求头和文件的 ETag,如果相同则返回 304 Not Modified。如果都不匹配,则设置 Last-Modified 和 ETag 响应头,并返回文件内容。

这样,通过使用 Last-Modified 和 If-Modified-Since 以及 ETag 和 If-None-Match,可以实现基于协商的缓存机制,减少不必要的数据传输和服务器负载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值