Web开发中的强缓存和协商缓存策略(二)
Web开发中的强缓存和协商缓存策略(二)
一. 相关参数
1. 强缓存
-
Expires
Expires
是HTTP/1.0
中定义的一个响应头字段,它表示资源的过期时间,即在这个时间之前,浏览器可以直接从浏览器缓存中获取资源,而不需要向服务器发送请求。Expires
的值是一个GMT格式的时间字符串,例如:response.setHeader('Expires',new Date(Date.now()+3600000).toUTCString());
上面代码表示缓存时间设置为1小时,即在1小时之后,浏览器会向服务器发送请求获取最新的资源。
-
Cache-Control
Cache-Control
是HTTP/1.1
中新增的缓存控制方式,它可以更加灵活地控制缓存行为。Cache-Control
的值可以是多个指令,每个指令之间用逗号分隔,例如:response.setHeader('Cache-Control','max-age=3600,public');
上面代码表示缓存设置时间为1小时,并允许其他用户共享缓存。
指令表示 max-age 指定缓存的最大有效时间,单位为秒 no-cache 表示缓存需要重新验证,即每次都需要向服务器发送请求 no-store 表示禁止缓存,每次都需要向服务器发送请求 public 表示允许其他用户共享缓存 private 表示只允许当前用户使用缓存
综上所述,Expires
和Cache-Control
都是强缓存的参数,可以通过设置不同的值来控制缓存行为。在实际开发中,建议使用Cache-Control
来代替Expires
,因为Cache-Control
的优先级更高,而且可以更加灵活地控制缓存行为。
2. 协商缓存
-
Last-Modified
Last-Modified
表示资源的最后修改时间,服务器在响应请求时会将该参数返回给客户端。客户端在下一次请求时会将该参数作为If-Modified-Since
的值发送给服务器,服务器会比较该值和资源的最后修改时间,如果相同则返回304 Not Modified
,否则返回新资源。const express = require('express'); const app = express(); app.get('/api/data', (req, res) => { let data = { name: 'Tom', age: 20 }; let lastModified = new Date('2023-06-08'); if (req.headers['if-modified-since'] === lastModified.toUTCString()) { res.status(304).end(); } else { res.set('Last-Modified', lastModified.toUTCString()); res.json(data); } }) app.listen(3000, () => { console.log('http://127.0.0.1:3000', '端口启动中......'); })
-
ETag
ETag
表示资源的唯一标识符,服务器在响应请求时会将该参数返回给客户端。客户端在下一次请求时会将该参数作为If-None-Match
的值发送给服务器,服务器会比较该值和资源的ETag
值,如果相同则返回304 Not Modified
,否则返回新的资源。const express = require('express'); const app = express(); app.get('/api/data', (req, res) => { let data = { name: 'Tom', age: 20 }; let etag = '123456789'; if (req.header['if-none-match'] === etag) { res.status(304).end(); } else { res.set('ETag', etag); res.json(data); } }) app.listen(3000, () => { console.log('http://127.0.0.1:3000', '端口启动中......'); })
-
Cache-Control
Cache-Controle
表示缓存控制的指令,可以设置缓存的过期时间、是否允许缓存、是否允许缓存的内容被修改等。常见的指令包括max-age
,no-cache
,no-store
等。const express = require('express'); const app = express(); app.get('/api/data', (req, res) => { let data = { name: 'Tom', age: 20 }; res.set('Cache-Control', 'max-age=3600'); res.json(data); }) app.listen(3000, () => { console.log('http://127.0.0.1:3000', '端口启动中......'); })
-
Expires
Expires
表示资源的过期时间,服务器在响应请求时会将该参数返回给客户端。客户端在下一次请求时会比较该值和当前时间,如果资源已经过期则发送新的请求,否则使用缓存的资源。const express = require('express'); const app = express(); app.get('/api/data', (req, res) => { let data = { name: 'Tom', age: 20 }; let expires = new Date(Date.now() + 3600000); res.set('Expires', expires.toISOString()); res.json(data); }) app.listen(3000, () => { console.log('http://127.0.0.1:3000', '端口启动中......'); })
二. 协商缓存结合axios的实际运用
1. 创建axios实例
首先,我们需要创建一个axios
实例,可以通过axios.create()
方法来创建。在创建实例时,可以设置一些默认参数,例如请求的基础URL和超时时间等。
import axios from 'axios';
const instance = axios.create({
baseURL: 'https://example.com/api',
timeout: 5000
});
2. 添加请求拦截器
接下来,我们需要添加一个请求拦截器,在请求头中添加缓存控制参数。这些参数包括Cache-Control
、Pragma
、If-Modified-Since
和If-None-Match
等。这些参数用于告诉服务器我们需要进行缓存控制,并且不需要缓存。
instance.interceptors.request.use(config => {
config.headers['Cache-Control'] = 'no-cache';
config.headers['Pragma'] = 'no-cache';
config.headers['If-Modified-Since'] = '0';
config.headers['If-None-Match'] = '';
return config;
}, error => {
return Promise.reject(error);
});
3. 添加响应拦截器
接下来,我们需要添加一个响应拦截器,在响应头中获取缓存控制参数。这些参数包括Cache-Control
、Expires
、Last-Modified
和ETag
等。根据这些参数,我们可以判断是否需要缓存,并且可以将响应数据缓存到本地。
instance.interceptors.response.use(response => {
const cacheControl = response.headers['cache-control'];
const expires = response.headers['expires'];
const lastModified = response.headers['last-modified'];
const etag = response.headers['etag'];
// 判断是否需要缓存
if (cacheControl && cacheControl.includes('no-cache')) {
return response.data;
}
// 判断是否命中缓存
if (response.status === 304) {
return localStorage.getItem(response.config.url);
}
// 将响应数据缓存到本地
localStorage.setItem(response.config.url, JSON.stringify(response.data));
return response.data;
}, error => {
return Promise.reject(error);
});
4. 发送请求
最后,我们可以使用axios实例来发送请求,例如发送一个GET请求:
instance.get('/data').then(response => {
console.log(response);
}).catch(error => {
console.log(error);
});
5. 将代码整合
//引入axios
import axios from 'axios'
//创建axios实例
const instance = axios.create({
baseURL: 'http://example.com/api',
timeout: 5000
})
//添加请求拦截器
instance.interceptors.request.use(config => {
//在请求头中添加缓存控制参数
config.headers['Cache-Control'] = 'no-cache';
config.headers['Pragma'] = 'no-cache';
config.headers['If-Modified-Since'] = '0';
config.headers['If-None-Match'] = '';
}, error => {
return Promise.reject(error);
})
//添加响应拦截器
instance.interceptors.response.use(response => {
//在请求头中获取缓存控制参数
const cacheControl = response.headers['cache-control'];
const expires = response.headers['expires'];
const lastModified = response.headers['last-modified'];
const etag = response.headers['etag'];
//判断是否需要缓存
if (cacheControl && cacheControl.includes('no-cache')) {
return response.data;
}
//判断是否命中缓存
if (response.status === 304) {
return localStorage.getItem(response.config.url);
}
//将响应数据缓存到本地
localStorage.setItem(response.config.url, JSON.stringify(response.data));
return response.data;
}, error => {
return Promise.reject(error);
})
//发送get请求
instance.get('/data').then(response => {
console.log(response);
}).catch(error => {
console.log(error)
})
在请求拦截器中,我们添加了四个请求头参数,分别是Cache-Control
、Pragma
、If-Modified-Since
和If-None-Match
。这些参数用于告诉服务器我们需要进行缓存控制,并且不需要缓存。如果服务器返回的响应头中包含了缓存控制参数,我们就可以根据这些参数来判断是否需要缓存。
在响应拦截器中,我们首先获取了响应头中的缓存控制参数,然后根据这些参数来判断是否需要缓存。如果需要缓存,我们就将响应数据缓存到本地。如果不需要缓存,我们就直接返回响应数据。如果服务器返回的状态码是304,说明命中了缓存,我们就可以从本地缓存中获取数据。
最后,我们发送了一个GET请求,并在控制台中输出了响应数据。开发者可以根据实际情况来修改请求头参数和响应头参数,以实现更加灵活的缓存控制。