HTTP缓存是一种用于优化网站性能和减少网络流量的重要机制。通过使用HTTP缓存,浏览器可以在再次访问同一网站时,避免重新请求相同的资源,而是从本地缓存中加载资源。这不仅可以加速网站加载速度,还可以减少网络流量和服务器负载。
在本文中,我将介绍HTTP缓存的工作原理以及如何使用HTTP头来控制缓存。我还将提供一些示例代码,以帮助您更好地理解HTTP缓存的实际实现。
HTTP缓存的工作原理
HTTP缓存分为两种类型:强制缓存和协商缓存。当浏览器第一次请求资源时,服务器可以使用HTTP响应头控制缓存策略。
强制缓存
强制缓存是指在指定时间内,浏览器不会再向服务器发送请求,而是从本地缓存中加载资源。这可以通过在HTTP响应头中设置Cache-Control
或Expires
字段来实现。
Cache-Control
字段是HTTP/1.1中最常用的控制缓存的头字段。它支持一系列的指令,包括max-age
、no-cache
和no-store
等。max-age
指令表示资源在缓存中的有效时间,单位为秒。例如,如果您希望浏览器缓存资源1个小时,您可以设置Cache-Control: max-age=3600
。no-cache
指令表示浏览器必须与服务器确认资源是否已更改。no-store
指令表示缓存不应存储任何版本的请求或响应。
Expires
字段是HTTP/1.0中用于控制缓存的头字段。它表示资源在缓存中的过期时间,以GMT格式的日期表示。例如,Expires: Tue, 10 Jul 2023 08:44:30 GMT
表示资源在此日期之后过期。如果同时设置了Cache-Control: max-age
和Expires
,则Cache-Control
会覆盖Expires
。
协商缓存
协商缓存是指浏览器向服务器发送条件请求,服务器根据资源是否更改返回304 Not Modified或200 OK响应。协商缓存可以通过在HTTP响应头中设置ETag
或Last-Modified
字段来实现。
ETag
是服务器为每个资源分配的唯一标识符。当浏览器请求资源时,服务器会在HTTP响应头中返回ETag
字段。浏览器在再次请求相同资源时,将在HTTP请求头中包含If-None-Match
字段,并将上次收到的ETag
值作为参数。如果资源未更改,服务器将返回304 Not Modified响应。
Last-Modified
字段是资源上次修改的时间。当浏览器请求资源时,服务器会在HTTP响应头中返回Last-Modified
字段。浏览器在再次请求相同资源时,将在HTTP请求头中包含If-Modified-Since
字段,并将上次收到的Last-Modified
值作为参数。如果资源未更改,服务器将返回304 Not Modified响应。
控制HTTP缓存
为了控制HTTP缓存,我们可以在服务器端设置HTTP响应头。下面是一些常用的HTTP头字段及其作用:
Cache-Control
: 控制强制缓存的行为,例如设置max-age
指令来控制资源在缓存中的有效时间。Expires
: 控制强制缓存的过期时间,但是已被Cache-Control
所取代。ETag
: 控制协商缓存的唯一标识符。Last-Modified
: 控制协商缓存的资源上次修改时间。
以下是一些示例代码,展示如何在Node.js中设置HTTP响应头:
// 强制缓存示例
app.get('/static/image.png', (req, res) => {
// 设置缓存时间为1小时
res.setHeader('Cache-Control', 'max-age=3600');
// 或者使用Expires字段,表示资源在1小时后过期
// res.setHeader('Expires', new Date(Date.now() + 3600 * 1000).toUTCString());
// 发送图片文件
res.sendFile('/path/to/image.png');
});
// 协商缓存示例
app.get('/api/data.json', (req, res) => {
const data = { foo: 'bar' };
const lastModified = new Date('2022-05-09T00:00:00.000Z');
// 设置Last-Modified头字段
res.setHeader('Last-Modified', lastModified.toUTCString());
// 如果浏览器发送了If-Modified-Since头字段,并且上次修改时间与资源相同,返回304 Not Modified
if (req.headers['if-modified-since'] && new Date(req.headers['if-modified-since']).getTime() === lastModified.getTime()) {
return res.status(304).end();
}
// 如果资源未更改,返回200 OK响应,否则返回数据和ETag头字段
const etag = crypto.createHash('md5').update(JSON.stringify(data)).digest('hex');
if (req.headers['if-none-match'] === etag) {
return res.status(304).end();
} else {
res.setHeader('ETag', etag);
return res.json(data);
}
});
结论
HTTP缓存是一种优化网站性能和减少网络流量的重要机制。我们可以使用HTTP头字段来控制缓存策略,包括强制缓存和协商缓存。在实际开发中,我们应该根据实际情况选择适当的缓存策略,以提高用户体验和降低服务器负载。