获取中...

-

Just a minute...

开始前的碎碎念

最近加班真的很严重,组里同事们都已经苦不堪言。业务交付压力非常大,根本没时间去磨练本领,学习技术。真的很讨厌这种没有成长的日子,每天被业务需求赶着跑。每天下班之后,本来应该用于提升自我的时间也被压榨用来写业务代码。

希望组里能早日摆脱现状,不然就只能润了

很多人应该都听过http缓存,也是比较常问的面试题吧。还记得我当时什么也不会,刷面经的时候就看到什么http状态码里的304,然后就顺着去搜了一下,搜到了什么协商缓存,看了一下,看的云里雾里。主要还是当时真的欠缺太多基本知识了,搜到的博客里面又都没讲这些基础的点。所以我这次想来通俗的讲一讲,http缓存。注意,本文中所指的服务器,绝大部分都是前端的,返回给你html文件等等的那个服务器,而不是部署着接口的后端服务器。

为什么需要http缓存

理解静态资源

我们都知道,访问一个网站,浏览器会向网站服务器发送很多http请求,去请求html文件,css文件,js文件等等。这些文件都是静态资源。静态资源,其实就是服务器上的文件罢了,不经常变化。你写一个网站的前端代码,写好了部署上去,就不变了。除非你重新部署,上面的文件才变。不像你请求接口,去查数据库里面的数据,那是经常变化的。

就因为静态资源不常变,所以我们可以把它们缓存起来。这样下次再请求的时候,缓存没过期的话,就可以直接从缓存里面读静态资源,会比从服务器再收一次静态资源快上很多。

注意:http缓存通常只针对get请求。这也很合理,因为浏览器访问网站,获取静态资源时,发送的请求都是get。至于你访问接口,就由你自己控制了。我的评价是接口都可以用post访问。

如何判断缓存是否过期

http缓存有两种:强缓存和协商缓存。流程省流:先强缓存,再协商缓存,再重新向服务器请求。

省流

通俗来说,浏览器向服务器请求静态资源的时候,服务器会说,你多久之内不要再来问我这个问题。于是这个时间内,每当浏览器需要用这个资源时,都会用第一次服务器给他的那份,这就是强缓存。

过了这个时间以后,强缓存失效了。浏览器会再去问服务器要这个资源,但是它问的时候会带上两个问题:

  1. 你上次给我的东西,哈希值是这个,你看看变了没
  2. 你上次给我的东西,是某个时间更新的,你看看还是不是最新的

服务器根据这两个问题来判断,浏览器的缓存还能不能用。如果能,服务器返回给浏览器的http状态码是304,意思就是和上次一样,我就不再给你一份了。如果不能,则服务器会重新发一份静态资源给浏览器。这就是协商缓存

强缓存

强缓存就是指,你第一次请求静态资源的时候,服务器返回给你的response header里面如果带下面的两个字段之一:expires或者cache-control,则浏览器会用强缓存规则判断缓存是否过期。expires是直接写死的过期时间,下次再发请求的时候,取当前时间和过期时间比较,来判断是否过期。而cache-control下面的max-age字段则是指定了一个时长。下次请求的时候,会看距离上次过了多久,比较时长来判断是否过期。

expires来自http1.0,cache-control的max-age来自http1.1 。expires的缺陷是没考虑时区问题。客户端和服务端的所处时区不一致时,expires是服务端所在时区的时间,而客户端会把它当成是自己所在时区的时间。

看到这里我们可以知道,强缓存的过期时间是服务器那边人为控制的,人为指定了这个缓存能有效多久。如果缓存没过期,我直接问都不问服务器。所以这个时间设定不宜太长,不然即便这些静态资源被更新了,用户也拿不到,因为用户一直在读本地的缓存。

协商缓存

当强缓存失效的时候,浏览器还会再挣扎一下,走协商缓存。前提是第一次返回的静态资源的响应头里面有下面两个字段之一:etag或者last-modified。etag可以理解为是这个静态资源的哈希值,内容变化会导致etag的变化。last-modified是这个静态资源上次被修改的时间。

等到第二次请求这个静态资源时,浏览器会向服务器发一个请求,这次请求头里面的if-none-match的值为上一次的response的etag,if-modified-since值为上一次response的last-modified。服务器收到这个请求,会再去看一下服务器上的静态资源,它的etag和last-modified,然后自己根据浏览器传过来的etag和last-modified,判断一下浏览器那边的缓存是否还能用。如果还能用,也就是没过期,就返回一个http code304。如果不能用,就返回最新的静态资源过去(当然http code是200)。

至于服务器如何根据etag和last-modified判断,这个是看服务器具体怎么实现的,各大框架应该都已经有现成的实现了。反正单独看两个字段的话,肯定是比较etag是否一致,和last-modified值是否相同了。但是二者的优先级,是依靠具体实现的。etag的准确度肯定更高。如果在last-modified的最小时间精度内,文件被修改了多次,last-modified是区分不出来的。而且无谓的修改也会导致last-modified的改变,即使修改并没有改动到文件的内容。所以通常建议以etag为准。

相关文章
评论
分享
  • 发布一个npm包的踩坑

    试着自己发布了一个npm包,记录一下自己踩的坑 package.json首先npm init,然后添加type:module字段,将其定义为一个es6模块。然后在files字段设置要发布上去的内容,比如dist文件夹。 接下来将开发用...

    发布一个npm包的踩坑
  • 关于SPA与SSR的简单介绍

    本文将简要介绍几个概念,如SPA, CSR, SSR, 前端路由。适合小白,我将用浅显又生动的话语来介绍这些概念。 什么是SPASPA(single page application)单页应用,占了现如今web应用的绝大多数。其意思就...

    关于SPA与SSR的简单介绍
  • 前端知识随手记录

    最近几个月被业务需求搞的要死,已经到了周末两天都要去加班的地步了。也没机会像之前那样,晚上下班之后到家学习一两个小时了。最近被逼急了,想着这样加班岂不是永远没有学习的时间,没有学习怎么能提升自己,于是晚上决定十一点到家也要翻翻书,哪...

    前端知识随手记录
  • 动手实现react-ssr 2

    仓库链接:本篇代码 运行方法参考readme,请使用pnpm,因为本次使用的rspack尚未推出1.0版本,预计后续可能会有很多breakchange,所以lock文件至关重要,而我只上传了pnpm的lock,非常抱歉。 环境:no...

    动手实现react-ssr 2
  • 动手实现react ssr

    关于ssr相关的介绍,可以移步之前的一篇博文,本文不再赘述 日常工作中,我们可能都接触过ssr,不过我们可能通常是借助于框架(例如Next.js)的支持来完成ssr。今天我想尝试,摆脱高度封装的前端框架,只依赖react相关的库,来实...

    动手实现react ssr
  • 基于tapable来模拟webpack插件机制

    前两天看到ByteFE公众号发了篇文章,从源码去讲webpack。我之前也从很多方面去学习webpack,只是源码一直没太看得进去,这一次我想仔细地读一读。 简要介绍tapable说实话,之前看webpack源码一直没看的太懂,...

    基于tapable来模拟webpack插件机制
  • 深入js——作用域,作用域链,执行栈(一)

    最近在补js基础。当初自学js的时候,总是感觉学的不扎实。只能说不去上手,再怎么死读书,也理解不了。积累了经验,然后自己去思考,这个时候再去看理论,就容易理解了。 感觉工作一年以来,确实学到了很多,但是过于专注于应用方面的知识,反倒...

    深入js——作用域,作用域链,执行栈(一)
  • webpack运行时代码简要分析

    开个坑,主要也是怕自己后面忘了 简单写写,有空了补上 __webpack_modules是一个数组,每个元素都是一个函数,函数接受三个参数:第一个参数module好像没用到,第二个是一个对象(会把本模块要导出的属性,赋值给这个对象),...

    webpack运行时代码简要分析
  • webpack动态加载原理简述

    为什么需要动态加载上一篇讲我写webpack针对markdown的loader的时候,提到了希望能动态加载以优化性能。篇幅原因没有展开说,打算单独写一篇文章讲一下。 当我们访问网站的时候,浏览器会向服务器请求页面资源。首先请求的当然是...

    webpack动态加载原理简述
  • 编写一个简单的webpack loader的踩坑

    因为觉得hexo框架搭的博客功能一般,就有了想要自己写一个博客的想法。然后就想着如果把markdown文件也放到项目里的话,会比较方便,发现需要编写一个加载markdown的loader,于是就有了这篇博客,来记录一下踩过的坑和收获...

    编写一个简单的webpack loader的踩坑
Please check the parameter of comment in config.yml of hexo-theme-Annie!