[实战验证] http缓存(无代理服务器)

栏目: 后端 · 前端 · 发布时间: 5年前

内容简介:最近看了不少关于客户端缓存机制的文章,大概弄明白了整个原理,但是对于中间一些细节一直有点迷糊,下面的内容是自己做的验证

最近看了不少关于客户端缓存机制的文章,大概弄明白了整个原理,但是对于中间一些细节一直有点迷糊,下面的内容是自己做的验证

二. 准备工作

http缓存的基本情况可以看看下这些文章

前端之浏览器缓存,一次搞定

前端也要懂Http缓存机制

常见的影响缓存的配置有以下几个:

  1. 原服务器的 Expires
  2. 原服务器的 Cache-Control
  3. 代理服务器(nginx) Expires
  4. 代理服务器(nginx) proxy_cache_valid
  5. 代理服务器(nginx) proxy_cache_path 中的 inactive

当前这篇会先验证无代理服务器的情况,有代理的情况放在之后验证

配置说明

原服务器的 Cache-Control

名称 说明
private 客户端可以缓存,代理服务器不可以缓存
public 客户端和代理服务器都可以缓存
max-age=t 缓存内容将在t秒后失效
no-cache 使用协商缓
no-store 不使用缓存

原服务器的 Expires

这是http 1.0的属性,现在应该用的少了;该属性设置的是一个过期时间,过期时间内命中强缓存;过期时间外,协商缓存

三. 验证

以下是我准备验证的问题

  1. 原服务器的 Cache-Control 不同属性的实际情况
  2. 原服务器的 Expires 的实际情况
  3. 不使用代理服务器的情况下,原服务器的 ExpiresCache-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();
})
复制代码

以下验证可以得出结论:

  1. max-age未过期 -> 命中强缓存
  2. max-age过期 -> 资源未修改 -> 命中协商缓存
  3. max-age过期 -> 资源已修改 -> 服务器获取资源
  4. no-cache -> 资源未修改 -> 命中协商缓存
  5. no-cache -> 资源已修改 -> 服务器获取资源
  6. 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-ControlStatus 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';
}
复制代码

以下验证可以得出结论:

  1. Expires未过期 -> 命中强缓存
  2. Expires过期 -> 资源未修改 -> 命中协商缓存
  3. 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-ControlExpires 同时设置的情况下, 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-ControlExpires 同时存在

  • 只有Cache-Control生效

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Practical JavaScript, DOM Scripting and Ajax Projects

Practical JavaScript, DOM Scripting and Ajax Projects

Frank Zammetti / Apress / April 16, 2007 / $44.99

http://www.amazon.com/exec/obidos/tg/detail/-/1590598164/ Book Description Practical JavaScript, DOM, and Ajax Projects is ideal for web developers already experienced in JavaScript who want to ......一起来看看 《Practical JavaScript, DOM Scripting and Ajax Projects》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具