P15:node实现静态服务器 ~ 缓存

476 阅读3分钟

相关文章

当客户端发起一个http请求的时候,服务器会相应并返回相应的结果。但是http协议在实际工作中会更加智能,静态资源的情况下会极大情况下利用缓存。对于网站来说,缓存是达到高性能的重要组成部分。

缓存

大致流程如下

  1. 首先客户端发起http请求
  2. 客户端会先检查本地缓存是否存在
    • 2.1 如果不存在本地缓存
      • 2.1.1 向服务器请求资源
      • 2.1.2 协商缓存(有效缓存时长等), 返回响应结果
    • 2.2 如果存在本地缓存
      • 2.2.1 缓存未失效,使用本地缓存,不向服务端发起正式请求
      • 2.2.2 缓存失效
        • 2.2.2.1 数据改变,发起请求,协商缓存(有效缓存时长等), 返回响应结果
        • 2.2.2.2 数据未改变, 返回客户端code status 304 并且使用本地缓存

设置头字段介绍

  • 通用首部字段(即请求报文和响应报文都能用的字段)

    头部名称 说明
    Pragma http1.0,值为“no-cache”时禁用缓存
    Cache-Control 返回一个相对与上一次访问的间隔时间
  • 请求首部字段

    字段名称 说明
    If-Match 比较ETag是否一致 与 If-None-Match 基本一致
    If-None-Match 比较ETag是否不一致
    If-Modified-Since 比较资源最后更新的时间是否一致
    If-Unmodified-Since 比较资源最后更新的时间是否不一致
  • 响应头部字段

    字段名称 说明
    ETag 资源的匹配信息
  • 实体首部字段

    字段名称 说明
    Expires http1.0,实体主体过期的时间
    Last-Modified 资源的最后一次修改的时间

coding

  • config/defaultConfig

    module.exports = {
      // 主机名称
      hostname: '127.0.0.1',
      // 端口号
      port: 6969,
      // 当前文件夹
      root: process.cwd(),
      // 配置压缩类型
      compress: /\.(html|js|css|md)/,
      // 缓存配置
      cache: {
        maxAge: 600, // 单位是s 不是ms 注意
        expires: true,
        cacheControl: true,
        LastModified: true,
        etag: true
      }
    }
    
  • /header/cache.js

    const { cache } = require('../config/defaultConfig')
    
    function refreshRes(stats, res) {
      // 引入配置项
      const { maxAge, expires, cacheControl, LastModified, etag } = cache
      // 如果支持 exprires
      if (expires) {
        res.setHeader('Expires', (new Date(Date.now() + maxAge * 1000)).toUTCString())
      }
      // 如果支持 cacheControl
      if (cacheControl) {
        res.setHeader('Cache-Control', `public, max-age=${maxAge}`)
      }
      // 如果支持 LastModified
      if (LastModified) {
        res.setHeader('Last-Modified', stats.mtime.toUTCString())
      }
      // 如果支持 Etag
      if (etag) {
        res.setHeader('ETag', `${stats.size}-${stats.mtime.toUTCString()}`) // mtime 需要转成字符串,否则在 windows 环境下会报错
      }
    }
    
    module.exports = function isFresh(stats, req, res) {
      refreshRes(stats, res)
      const LastModified = req.headers['if-modified-since']
      const etag = req.headers['if-none-match']
    
      // 如果均不存在
      if (!LastModified && !etag) {
        return false
      }
      // 如果存在 LastModified 并且过期
      if (LastModified && LastModified !== res.getHeader('Last-Modified')) {
        return false
      }
      // 如果存在 etag 并且过期
      if (etag && etag !== res.getHeader('ETag')) {
        return false
      }
      // 使用缓存
      return true
    }
    
  • route.js 修改

close