FrankKai / FrankKai.github.io

FE blog

Home Page:https://frankkai.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

HTTP之强缓存和协商缓存

FrankKai opened this issue · comments

关于强缓存和协商缓存的理论知识和express.js下的实践,政采云前端团队的这篇文章已经非常详尽了:图解 HTTP 缓存

什么是强缓存

  • 不需要发送请求到服务端,直接读取浏览器本地缓存
  • 强缓存分为Disk Cache和Memory Cache,由浏览器决定存放
  • 强缓存通过Expires、Cache-Control和Pragma 3个头决定

什么是协商缓存

  • 强缓存失效并且请求头中设置了If-Modified-Since或者If-None-Match时触发
  • 协商缓存是通过带着上面2个请求头到服务器验证是否命中协商缓存,若命中返回304,加载浏览器缓存,并且响应头设置Last-Modified和ETag

二者区别

协商缓存可以说是一种通过访问服务器去判断是否走浏览器本地缓存的方式,在服务器资源更新时,可以使得浏览器获取到最新的资源;而强缓存是不叫简单粗暴的,直接根据过期时间进行判定

强缓存和协商缓存流程图

image

图来自图解 HTTP 缓存

刚好我最近也在对这一块的内容做补充和总结,受到这篇优质博文的启发,于是有了这篇博文。

那么在这篇博文中会看到什么呢?

  • 强缓存和协商缓存需要注意的细节
  • HTTP 强缓存和协商缓存之 Koa 实战
    • Expires,Cache-Control, Pragma
    • If-Modified-Since&&Last-Modified
    • If-None-Match&&ETag

强缓存和协商缓存需要注意的细节

报文头类型

报文头 请求头 响应头
Expires
Pragma
Cache-Control
If-Match/If-None-Match
ETag
If-Modified-Since
Last-Modified

报文头优先级(圆括号为响应头)

强缓存:Pragma > Cache-Control > (Expires)

协商缓存:If-None-Match(ETag) > If-Modified-Since(Last Modified)

如果强缓存是新鲜的,优先强缓存。

如果强缓存是不新鲜的,判断有无协商缓存:

若上一次请求中有ETag,在If-None-Match带上ETag value;

若上一次请求中没有ETag,判断上一次请求响应中是否有Last-Modified,在If-Modified-Since中带上Last-Modified value;

若资源没有更新,状态码为304走浏览器缓存;若为200,走协商缓存,返回更新后的资源。

If-Match与If-None-Match区别是什么?

  • If-Match在服务器上有对应ETag的资源时返回新的资源
  • If-None-Match在服务器上没有对应ETag的资源时返回新的资源
  • 二者都是条件请求,相当于HTTP协议通过请求头在做If-else判断

HTTP 强缓存和协商缓存之 Koa 实战

Expires

代码:

const Koa = require("koa");
const app = new Koa();

app.use((ctx) => {
  ctx.body = "HTTP强缓存之Expires";
  ctx.set("Expires", "Mon, May 11 2020 22:10:14 GMT");
});

app.listen(3000);
console.log("应用运行在localhost:3000");

首次请求:
image

第二次请求来自强缓存:
image

Cache-Control

代码:

const Koa = require("koa");
const app = new Koa();

app.use((ctx) => {
  ctx.body = "HTTP强缓存之Cache-Control";
  ctx.set("Cache-Control", "public,max-age=60");
});

app.listen(3000);
console.log("应用运行在localhost:3000");

首次请求:
image

第二次请求来自强缓存:
image

Pragma

代码:

const Koa = require("koa");
const app = new Koa();

app.use((ctx) => {
  ctx.body = "HTTP强缓存之Pragma";
  ctx.set("Pragma", "no-cache");
});

app.listen(3000);
console.log("应用运行在localhost:3000");

首次请求:
Pragma
image

第二次请求:
image

If-Modified-Since&&Last-Modified

代码:

const Koa = require("koa");
const app = new Koa();

app.use((ctx) => {
  ctx.body = "HTTP协商缓存之If-Modified-Since&&Last-Modified";
  ctx.set({
    "Last-Modified": "Mon, May 11 2020 22:20:14 GMT",
  });
});

app.listen(3000);
console.log("应用运行在localhost:3000");

第一次请求:
image

第二次请求:
image

If-None-Match&&ETag

代码:

const conditional = require("koa-conditional-get");
const etag = require("koa-etag");
const Koa = require("koa");
const app = new Koa();

app.use(conditional());
app.use(etag());

app.use((ctx) => {
  ctx.body = "HTTP协商缓存之If-None-Match&&ETag";
});

app.listen(3000);
console.log("应用运行在localhost:3000");

首次请求:
image

第二次请求来自协商缓存:
image

期待和大家交流,共同进步,欢迎大家加入我创建的与前端开发密切相关的技术讨论小组:

努力成为优秀前端工程师!