74-http-24-缓存验证

概述

当我们给Catch-Control 设置了 no-catch 后,每次浏览器对这个资源的请求时,都会到服务器端进行资源验证,验证完之后,如果确定这个资源可以使用缓存,浏览器才会读取本地的缓存。

缓存验证流程

方式

验证资源是否需要更新有两种方式: Last-Modified 与 Etag

Last-Modified

上次修改时间。主要配合If-Modified-Since 或者 If-Unmodified-Since 这两个Header 使用。

通过对比请求首部字段If-Modified-Since和实体首部字段 Last-Modified,来判断是否使用缓存。

如果我们请求的一个资源,它返回的Header 中有Last-Modified 并指定了一个时间。那么下次浏览器再发送这个请求的时候就会带上这个时间,并把它放在 If-Modified-Since中;服务器就可以根据If-Modified-Since值对比资源上次修改的时间,如果两个时间一致,说明请求的资源都没有过更新,那么就可以使用缓存

Etag

是一个更为严格的验证,通过数据签名的方式验证。主要配合 If-Match 或者 If-None-Match 使用。

它根据数据内容产生一个唯一的编码(数据不同,编码结果不同)。最典型的做法,是我们对数据内容做一个哈希计算。

当服务端加上Last-Modified,Etag,浏览器下次请求就会带上If-Modified-SinceIf-None-Match,来进行缓存验证。

使用缓存实例

test.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
    
</body>
<script src="/script.js"></script>
</html>

server.js

const http = require('http')
const fs = require('fs')

http.createServer(function (request, response) {
  console.log('request come', request.url)

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8')
    response.writeHead(200, {
      'Content-Type': 'text/html'
    })
    response.end(html)
  }

  if (request.url === '/script.js') {
    
    const etag = request.headers['if-none-match']
    if (etag === '777') {
      response.writeHead(304, {
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=2000000, no-cache',
        'Last-Modified': '123',
        'Etag': '777'
      })
      response.end()
    } else {
      response.writeHead(200, {
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=2000000, no-cache',
        'Last-Modified': '123',
        'Etag': '777'
      })
      response.end('console.log("script loaded twice")')
    }
  }
}).listen(8888)

console.log('server listening on 8888')

使用node server.js启动,在http://localhost:8888/上查看server.js的网络请求。

可以发现,状态码第一次是200,第二次及以后缓存范围期限内,都是304