• 聊聊Http 缓存机制


    Http 缓存机制

    Q:前端为什么要去了解http缓存机制呢?

    • 在偏C端的业务系统中,往往对于软件的性能要求会更高一些,软件的易用性,响应速度,首屏打开速度都会影响用户的体验感
    • 所以项目经理,产品经理都会对这个方面有较高的要求,更快的速度,更好的性能代表了更多的money
    • 而很多可以优化的地方都要前端工程师对于http缓存机制有更加深刻认识和了解

    Q:缓存机制只有http缓存么?使用它有啥好处?

    答案是否定的,缓存机制到处都存在,为了提高性能,有客户端缓存,服务端缓存,代理服务器缓存等

    但是对于我们前端而言,http缓存是我们前端可以接触到并实际使用的web性能优化手段

    (1)减少网络带宽消耗

    无论对于网站运营者或者用户,带宽都代表着金钱,过多的带宽消耗,只会便宜了网络运营商。当Web缓存副本被使用时,只会产生极小的网络流量,可以有效的降低运营成本。

    (2)降低服务器压力

    给网络资源设定有效期之后,用户可以重复使用本地的缓存,减少对源服务器的请求,间接降低服务器的压力。

    (3)减少网络延迟,加快页面打开速度

    答案是肯定的,对于最终用户,缓存的使用能够明显加快页面打开速度,达到更好的体验。

    Q:http缓存机制有哪几种类型?

    强制缓存

    • 命中缓存

      • 请求数据的时候命中缓存了(有缓存,且未失效),就直接从缓存中拿数据,不用与服务器进行交互
    • 没有命中缓存

      • 请求数据的时候没有命中(无缓存或者失效),就会向服务端发送请求,然后讲服务端返回的数据及缓存规则写入缓存
    • 使用场景

      • 持久性资源数据,可以使用该策略
    • status为灰色的是强制缓存,分为两种from memory cache 和 from disk cache,浏览器会优先读取内存中的数据

      • from memory cache
        • 存在于内存中
        • 读取速度相对更快
        • 进程关闭就会清空(关闭标签页就会清空)
        • 一般存储js文件及图片资源
      • from disk cache
        • 存在于硬盘当中
        • 读取速度相对较慢
        • 进程关闭也不会清空
        • 一般存储css文件
    • 配置参数

      • Expires
        • 这个参数的配置属于http1.0的参数
        • 值是一个时间绝对值(小于这个时间都会使用强制缓存)
      • Cache-Control
        • 这个参数的配置属于http1.1的参数
        • 值为几种情况
          • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
          • private:所有内容只有客户端可以缓存,Cache-Control的默认取值
          • no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
          • no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
          • max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
      • 如果两个参数都存在的话,Cache-Control 优先级大于Expires

    协商缓存

    • 强制缓存失效后,浏览器携带缓存标识(一般为(Last-Modified / If-Modified-Since和Etag / If-None-Match))向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程
    • 协商缓存生效
      • 服务器判断资源未更新,就会返回304状态码,客户端直接使用之前的缓存数据
    • 协商缓存不生效
      • 服务器判断资源更新,就会从数据库获取最新的数据,返回200状态码,客户端使用最新的数据并更新缓存
    • Last-Modified / If-Modified-Since
      • 值为一个标准时间,服务器会根据这个时间去比对资源
      • 消耗性能小
      • 精度只能到秒(密集请求可能会存在问题)
    • Etag / If-None-Match
      • 一个唯一的hash值,服务器会比较这个hash值是否一致
      • 性能消耗较大
      • 精度高,一般会优先考虑这个

    用户行为对浏览器缓存的控制

    1. 地址栏访问,链接跳转是正常用户行为,将会触发浏览器缓存机制;
    2. F5刷新,浏览器会设置max-age=0,跳过强缓存判断,会进行协商缓存判断;
    3. ctrl+F5刷新,跳过强缓存和协商缓存,直接从服务器拉取资源。

    实践

    1. 是否缓存依赖于接口响应头里面设置的参数(其实对于前端来说,操作有限,了解可以针对一些特定场景来解决问题)

    2. 下面是一个使用Nginx作为Web服务器的缓存配置

      location / {   
      	# 其它配置  ...   
      	if ($request_uri ~* .*[.](js|css|map|jpg|png|svg|ico)$) {    
      		#非html缓存1个月    
      		add_header Cache-Control "public, max-age=2592000";  
      	}   
      	if ($request_filename ~* ^.*[.](html|htm)$) {
      		#html文件使用协商缓存    
      		add_header Cache-Control "no-cache";  
      	} 
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    3. 配合webpack打包 contenthash的方案

      hash 计算与整个项目的构建相关;

      chunkhash 计算与同一 chunk 内容相关;(js和css在同一个chunk)

      contenthash 计算与文件内容本身相关.(文件内容发生改变,contenthash就会改变)

      module.exports = {
        output: {
          // 文件hash
          filename: '[name].[contenthash].js',
        },
        optimization: {
          moduleIds: 'deterministic',//避免因为模块解析顺序发生变化而导致文件 hash 值改变
          // runtime 单独打包为一个 chunk
          runtimeChunk: 'single',
          splitChunks: {
            cacheGroups: {
              // 第三方包打包为 vendors chunk,因为很少修改,有利长期缓存
              vendor: {
                test: /[\\/]node_modules[\\/]/,
                name: 'vendors',
                chunks: 'all',
              },
            },
          },
        },
      };
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    4. 大厂的解决方案(B站)

      1. html:no-cache
      2. JS文件:max-age=31536000(1年),文件命名带版本号或指纹信息,方便及时更新。
      3. CSS文件:max-age=31536000,文件命名带版本号或指纹信息,方便及时更新。
      4. 图片:max-age=31536000,文件命名带版本号或指纹信息,方便及时更新。
      5. XHR请求: no-cache

    总结

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jjedp6jd-1656411814643)(C:\Users\xiaziwei\AppData\Roaming\Typora\typora-user-images\image-20220627174947855.png)]

    注意点

    1. 缓存只能针对于get请求,对于post等对于数据库操作的请求类型是不支持的
    2. 缓存配置在响应体里,前端如果不涉及到后端的话,操作空间有限,只能与后端沟通哪些接口或者资源可以做缓存处理
    3. 缓存的目的是为了提供更好的体验和降低服务器压力,提高缓存命中率的同时,一定要保证数据的新鲜度
  • 相关阅读:
    【svn】svn分支(branch)如何同步主干(trunk)的代码?
    Linux性能分析——TOP命令详解
    Consul安装配置
    IL编织器 --- Fody
    C++STL——string类与模拟实现
    健身戴什么耳机,盘点几款健身佩戴的耳机推荐
    Tomcat多实例、负载均衡、动静分离
    Python学习笔记--属性的访问控制
    英语语法 — 被动语态
    【节能学院】智能操控装置在高压开关柜的应用
  • 原文地址:https://blog.csdn.net/weixin_42369612/article/details/125507705