内容简介:最近看了不少关于客户端缓存机制的文章,大概弄明白了整个原理,但是对于中间一些细节一直有点迷糊,下面的内容是自己做的验证
最近看了不少关于客户端缓存机制的文章,大概弄明白了整个原理,但是对于中间一些细节一直有点迷糊,下面的内容是自己做的验证
二. 准备工作
http缓存的基本情况可以看看下这些文章
常见的影响缓存的配置有以下几个:
-
原服务器的
Expires -
原服务器的
Cache-Control -
代理服务器(nginx)
Expires -
代理服务器(nginx)
proxy_cache_valid -
代理服务器(nginx)
proxy_cache_path中的inactive
当前这篇会先验证无代理服务器的情况,有代理的情况放在之后验证
配置说明
原服务器的 Cache-Control
:
| 名称 | 说明 |
|---|---|
| private | 客户端可以缓存,代理服务器不可以缓存 |
| public | 客户端和代理服务器都可以缓存 |
| max-age=t | 缓存内容将在t秒后失效 |
| no-cache | 使用协商缓 |
| no-store | 不使用缓存 |
原服务器的 Expires
:
这是http 1.0的属性,现在应该用的少了;该属性设置的是一个过期时间,过期时间内命中强缓存;过期时间外,协商缓存
三. 验证
以下是我准备验证的问题
-
原服务器的
Cache-Control不同属性的实际情况 -
原服务器的
Expires的实际情况 -
不使用代理服务器的情况下,原服务器的
Expires和Cache-Control同时存在,那个优先级高
1. 首先是无代理服务器的情况
验证方式是使用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}`);
})
复制代码
1.1 Cache-Control的各属性验证
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();
})
复制代码
以下验证可以得出结论:
- max-age未过期 -> 命中强缓存
- max-age过期 -> 资源未修改 -> 命中协商缓存
- max-age过期 -> 资源已修改 -> 服务器获取资源
- no-cache -> 资源未修改 -> 命中协商缓存
- no-cache -> 资源已修改 -> 服务器获取资源
- no-store -> 服务器获取资源
| 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 | 不使用缓存,直接从服务端获取资源 |
1.2 Expires验证
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未过期 -> 命中强缓存
- Expires过期 -> 资源未修改 -> 命中协商缓存
- Expires过期 -> 资源已修改 -> 服务器获取资源
| 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 | 强缓存过期,资源被修改,重新从服务器获取资源 |
1.3 Expires与Cache-Control优先级
结论: 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过期,直接获取服务端资源 |
四. 总结:
1. 只设置 Cache-Control
- max-age未过期 -> 命中强缓存
- max-age过期 -> 资源未修改 -> 命中协商缓存
- max-age过期 -> 资源已修改 -> 服务器获取资源
- no-cache -> 资源未修改 -> 命中协商缓存
- no-cache -> 资源已修改 -> 服务器获取资源
- no-store -> 服务器获取资源
2. 只设置 Expires
- Expires未过期 -> 命中强缓存
- Expires过期 -> 资源未修改 -> 命中协商缓存
- Expires过期 -> 资源已修改 -> 服务器获取资源
3. Cache-Control
与 Expires
同时存在
- 只有Cache-Control生效
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- SpringBoot 缓存实战
- Viewer模型加载本地缓存实战
- SpringBoot 实战 (十一) | 整合数据缓存 Cache
- EVCache缓存在 Spring Boot中的实战
- 原 荐 缓存架构之借助消息中间件RabbitMQ实现Redis缓存实时更新实战演练
- H5 和移动端 WebView 缓存机制解析与实战
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Game Engine Architecture, Second Edition
Jason Gregory / A K Peters/CRC Press / 2014-8-15 / USD 69.95
A 2010 CHOICE outstanding academic title, this updated book covers the theory and practice of game engine software development. It explains practical concepts and techniques used by real game studios,......一起来看看 《Game Engine Architecture, Second Edition》 这本书的介绍吧!