最近看了很多关于客户端缓存机制的文章,大概弄明白了整个原理,可是对于中间一些细节一直有点迷糊,下面的内容是本身作的验证javascript
前端之浏览器缓存,一次搞定html
Expires
Cache-Control
Expires
proxy_cache_valid
proxy_cache_path
中的inactive
当前这篇会先验证无代理服务器的状况,有代理的状况放在以后验证java
原服务器的Cache-Control
:node
名称 | 说明 |
---|---|
private | 客户端能够缓存,代理服务器不能够缓存 |
public | 客户端和代理服务器均可以缓存 |
max-age=t | 缓存内容将在t秒后失效 |
no-cache | 使用协商缓 |
no-store | 不使用缓存 |
原服务器的Expires
:nginx
这是http 1.0的属性,如今应该用的少了;该属性设置的是一个过时时间,过时时间内命中强缓存;过时时间外,协商缓存chrome
如下是我准备验证的问题:express
Cache-Control
不一样属性的实际状况Expires
的实际状况Expires
和Cache-Control
同时存在,那个优先级高[1-24 更新] 增长一个验证:json
验证方式是使用node的express启动一个服务后端
const fs = require('fs');
const path = require('path');
const express = require('express');
const app = express();
const port = 3030;
app.use(express.static(path.resolve(__dirname, './')));
app.get('/index', (req, res) => {
const html = fs.readFileSync(path.resolve(__dirname, './index.html'), 'utf-8');
res.send(html)
})
// cache验证
app.all('*', (req, res, next) => {
// res.header('Cache-Control', 'private');
// res.header('Cache-Control', 'public');
res.header('Cache-Control', 'max-age=20');
// res.header('Cache-Control', 'no-cache');
// res.header('Cache-Control', 'no-store');
next();
})
const questions = [
{
id: '000',
name: 'Rose'
},
{
id: '111',
name: 'Jack'
}
]
app.get('/api/data', (req, res) => {
res.status(200);
res.json(questions);
})
// 监听端口
app.listen(port, () => {
console.log(`success listen at ${port}`);
})
复制代码
ps:由于不存在代理服务器,因此public和private的区别如今是看不出来的,咱们以后和有代理的状况一块儿验证
// 单独验证Cache-Control
app.all('*', (req, res, next) => {
res.header('Cache-Control', 'max-age=30');
// res.header('Cache-Control', 'no-cache');
// res.header('Cache-Control', 'no-store');
next();
})
复制代码
如下验证能够得出结论:
Cache-Control | 请求延迟时间 | 资源是否改变 | If-None-Match(request) | ETag(respanse) | Status Code | 结论 |
---|---|---|---|---|---|---|
max-age=30 | 10s | 是 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 200 OK (from disk cache) | 强缓存未过时,命中强缓存 |
max-age=30 | 60s | 是 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"3a-LT60UfEg/Jmv4cmkNOAvZSUh6Qo" | 200 OK | 强缓存过时,资源被修改,从新从服务器获取资源 |
max-age=30 | 10s | 否 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 200 OK (from disk cache) | 强缓存未过时,命中强缓存 |
max-age=30 | 60s | 否 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 304 Not Modified | 强缓存过时,资源未修改,命中协商缓存 |
no-cache | 30s | 是 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"3a-LT60UfEg/Jmv4cmkNOAvZSUh6Qo" | 200 OK | 资源被修改,未命中协商缓存,从服务器获取资源 |
no-cache | 30s | 否 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 304 Not Modified | 资源未修改,命中协商缓存 |
no-store | 30s | 是 | 无 | W/"3a-LT60UfEg/Jmv4cmkNOAvZSUh6Qo" | 200 OK | 不使用缓存,直接从服务端获取资源 |
no-store | 30s | 否 | 无 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 200 OK | 不使用缓存,直接从服务端获取资源 |
ps1:若是这个Expires
字段后端没有处理过的话,返回的应该是GMT的标准时间Wed, 23 Jan 2019 09:52:55 GMT
,也就是格林威治的标准时间;而咱们通常使用的是本地时间Wed Jan 23 2019 18:06:15 GMT+0800 (中国标准时间)
,因此要作一下适当的处理
ps2:我是在chrome上用localhost上测试的,但不知道为何设置Expires
后,无论过没过时,无论有没有同时设置Cache-Control
,Status Code
状态一直是304的,据说好像是由于用了localhost的关系,这个与线上并不必定彻底一致;这里关于Expires
的测试我是加了nginx代理了以后的结果,不过代理的缓存没有设置
ps3:Expires
的结果就仅供参考吧,以上
const moment = require('moment');
// cache验证
app.all('*', (req, res, next) => {
res.header('Expires', getGLNZ());
next();
})
// 转换格林威治时间
function getGLNZ() {
return moment().utc().add(30, 's').format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT';
}
复制代码
如下验证能够得出结论:
Expires | 请求延迟时间 | 资源是否改变 | If-None-Match(request) | ETag(respanse) | Status Code | 结论 |
---|---|---|---|---|---|---|
当前时间+30s | 10s | 否 | 无 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 200 OK (from disk cache) | 强缓存未过时,命中强缓存 |
当前时间+30s | 60s | 否 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 304 Not Modified | 强缓存过时,资源未修改,命中协商缓存 |
当前时间+30s | 10s | 是 | 无 | W/"3a-LT60UfEg/Jmv4cmkNOAvZSUh6Qo" | 200 OK (from disk cache) | 强缓存未过时,命中强缓存 |
当前时间+30s | 60s | 是 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"3a-LT60UfEg/Jmv4cmkNOAvZSUh6Qo" | 200 OK | 强缓存过时,资源被修改,从新从服务器获取资源 |
结论:Cache-Control
优先级比Expires
优先级高
const moment = require('moment');
// cache验证
app.all('*', (req, res, next) => {
res.header('Cache-Control', 'max-age=60');
// res.header('Cache-Control', 'no-cache');
// res.header('Cache-Control', 'no-store');
res.header('Expires', getGLNZ());
next();
})
function getGLNZ(){
return moment().utc().add(30, 's').format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT';
}
复制代码
如下验证能够看出,在Cache-Control
与Expires
同时设置的状况下,Expires
是失效的
Expires | Cache-Control | 请求延迟时间 | 资源是否改变 | If-None-Match(request) | ETag(respanse) | Status Code | 结论 |
---|---|---|---|---|---|---|---|
当前时间+30s | max-age=60 | 10s | 否 | 无 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 200 OK (from disk cache) | Expires与Cache-Control都未过时,命中强缓存 |
当前时间+30s | max-age=60 | 40s | 否 | 无 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 200 OK (from disk cache) | Expires过时,Cache-Control未过时,命中强缓存 |
当前时间+30s | max-age=60 | 100s | 否 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 304 Not Modified | Expires与Cache-Control都过时,资源未修改,命中协商缓存 |
当前时间+30s | no-cache | 10s | 否 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 304 Not Modified | Expires未过时,可是命中协商缓存 |
当前时间+30s | no-cache | 60s | 否 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 304 Not Modified | Expires过时,命中协商缓存 |
当前时间+30s | no-store | 10s | 否 | 无 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 200 OK | Expires未过时,直接获取服务端资源 |
当前时间+30s | no-store | 60s | 否 | 无 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 200 OK | Expires过时,直接获取服务端资源 |
如下验证结论:
If-None-Match
与ETag
相同 -> 协商缓存If-None-Match
与ETag
不相同 -> 服务器获取资源资源是否改变 | If-None-Match(request) | ETag(respanse) | Status Code | 结论 |
---|---|---|---|---|
是 | W/"3a-LT60UfEg/Jmv4cmkNOAvZSUh6Qo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 200 OK | 服务器获取资源 |
否 | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | W/"37-W4vHvR7+YshQyC9DoyT14egVUqo" | 304 Not Modified | 命中协商缓存 |
Cache-Control
Expires
Cache-Control
与Expires
同时存在Cache-Control
与Expires
都未设置request
中的If-None-Match
与response
中的ETag
If-None-Match
与ETag
相同 -> 协商缓存If-None-Match
与ETag
不相同 -> 服务器获取资源Cache-Control no-cahce