HTTP05缓存控制

缓存控制

Expires

  • 设置过期时间 (http1.0的东西,现在用的少了)
1
2
3
// Wed, 30 Dec 2020 18:05:17 GMT
var date = new Date(Date.now()+1000*5).toGMTString()
res.setHeader('Expires',date)

存在问题是 : 服务器时间和你客户端时间不一致。

Pragma

  • 不要缓存,每次都重新拿
  • 优先级最高,一旦设置就不会走缓存
1
res.setHeader('Pragma','no-cache')

当 Pragma 和 Expires同时出现, Pragma优先级高

1
2
3
var date = new Date(Date.now()+1000*5).toGMTString()
res.setHeader('Expires',date)
res.setHeader('Pragma','no-cache')

Cache-Control

  • 设置过期时间戳
    • 解决了 Expires 时间不一致问题
1
2
// 10s后过期
res.setHeader('Cache-Control','max-age=10')

Cache-Control 为啥不能缓存 html

  • 访问 taobao
  • 你会发现 响应首页 的其他资源能被缓存,但是 这个首页html的响应头是
1
cache-control: max-age=0
  • 这是为了 解决网站改版的情况,浏览器自己设置的,如果缓存了,但是你走缓存就无法更新页面了

Cache-Control 其他值

1
2
3
4
5
6
// 代表不走缓存,即使浏览器里有缓存
cache-control: no-cache

// 代表不走缓存
// 资源可能中间有很多代理服务器(告诉代理服务器不要缓存)
cache-control: no-store

Last-Modified

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 当你访问服务器的时候,读取文件
// 获取文件有相关的信息,拿到——“修改时间”

// 这句代表你要重新找我拿,不走缓存,验证这个修改时间,如果变了 重新读取,没变返回304 从本地读取
// 不设置的时候,浏览器会缓存,就不会经过服务器验证了,直接从本地读取文件
res.setHeader('Cache-Control','no-cache')
// 如果没有这个字段,代表第一次请求
if(!req.headers['if-modified-since']){
// mtime 是修改时间
res.setHeader('Last-Modified',new Date(mtime).toGMTString())
res.writeHead(200,'OK')
res.end(data) // data是文件数据
}else{
let oldMtime = Date.parse(req.headers['if-modified-since'])
if(mtime>oldMtime){
// 文件修改了,重新读取吧
res.setHeader('Last-Modified',new Date(mtime).toGMTString())
res.writeHead(200,'OK')
res.end(data) // data是文件数据
}else{
// 文件没变,你用缓存吧
res.writeHead(304)
res.end()
}
}

案例1

1
2
3
4
5
6
7
8
9
10
11
12
13
res.setHeader('Cache-Control','no-cache')
res.setHeader('Last-Modified',new Date(mtime).toGMTString())
res.end(data) // data是文件数据

// no-cache 意思是 不要从本地缓存找 每次都找我要(每次都和服务器文件的mtime比对)
// 第一次请求的时候响应里设置 Last-Modified 和时间,并把文件返回
// 浏览器就会把这个时间缓存下来
// 之后的每次请求 都会带上 if-modified-since 的时间
// 但是发现 本地缓存信息里有 no-cache 就不会直接从本地读取,
// 而是带上 if-modified-since 和服务器文件的 mtime 比对,如果变了就重新读取,没变就走缓存


// no-cache 等价于 max-age=0

案例2,设置了 no-store

1
2
3
4
5
6
res.setHeader('Cache-Control','no-store')
res.setHeader('Last-Modified',new Date(mtime).toGMTString())
res.end(data) // data是文件数据

// no-store 意思是
// 你设置的 Last-Modified 响应报文不会被浏览器记录,每次都重新读取文件

ETag

  • 比如 a.css文件
1
2
3
body{
color:red;
}
  • 你修改了,修改时间变了
1
2
3
body{
color:red
}
  • 你又修改了,修改时间又变了
1
2
3
body{
color:red;
}

但是文件内容没变。但是 Last-Modified 只看时间,ETag代表 看文件内容是否变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 当你访问服务器的时候,读取文件
// 获取文件有相关的信息,生成——“md5值”

// 这句代表你要重新找我拿,不走缓存,验证这个 md5值,如果变了 重新读取,没变返回304 从本地读取
// 不设置的时候,浏览器会缓存,就不会经过服务器验证了,直接从本地读取文件

let md5 = crypto.createHash('md5');
res.setHeader('Cache-Control','no-cache')
// 如果没有这个字段,代表第一次请求
let oldETag = req.headers['if-none-match'];
if(!oldETag){
// 第一次请求
res.setHeader('Etag',md5.update(data).digest('base64'))
res.writeHead(200,'OK')
res.end(data) // data是文件数据
}else{
let newETag = md5.update(data).digest('base64')
if(newETag !== oldETag){
// 文件内容变了,重新读取吧
res.setHeader('Etag',newETag)
res.writeHead(200,'OK')
res.end(data) // data是文件数据
}else{
// 文件没变,你用缓存吧
res.writeHead(304)
res.end()
}
}

参考连接