浏览器http缓存问题

ops/2024/12/26 10:37:55/

一、什么是浏览器缓存

浏览器将请求过的资源(html、js、css、img)等,根据缓存机制,拷贝一份副本存储在浏览器的内存或者磁盘上。如果下一次请求的url相同时则根据缓存机制决定是读取内存或者磁盘上的数据还是去服务器请求资源文件

缓存通过url来判断,如果url不同则是新的资源。所以我们开发时前端会将一些js、css等文件在后面加hash值来避免资源更新时浏览器仍读取缓存文件,导致需要刷新才能获取新的资源的问题

这种做法虽然解决了js、css等文件的更新,这种加hash的就不在这篇文章说了,具体方法上网查即可,但是对于index.html这样的文件由于不能加hash值,则仍然会存在当资源更新了,但是仍然读取缓存文件的问题。

二、与缓存相关的状态码

200 ok从浏览器下载的最新资源
200 (from memory cache)不进行http请求,直接从浏览器内存中读取的资源,页面关闭,则资源释放,一般一些脚本、图片、文字等会存在内存中
200 (from disk cache)不进行http请求,直接从磁盘中读取的资源,页面关闭,资源仍然存在,除非清除缓存,一般一些非脚本文件会存在磁盘中,例如html、css文件
304 (not modified)请求了服务器,但是由于服务器资源没有更新,所以仍使用内存中的资源

三、缓存相关的http header介绍

http header介绍
cache-controlresponse header or request header;指定缓存机制,优先级最高
expiresresponse header or request header;指定缓存的过期时间(现在浏览器一般设置cache-control,设置expires是为了兼容http1.0)
last-modifiedresponse header;资源的最后修改时间
etagresponse header;资源的唯一标识符
if-modified-sincerequest header;缓存的服务器资源的最后修改时间
if-none-matchrequest header;缓存的服务器资源的唯一标识

1. 强缓存

不会进行http请求,读取的是内存中的资源,直到缓存失效

涉及到的状态码:

  • 200(from memory cache)
  • 200(from disk cache)

涉及到的http header: 

  • cache-control

优先级最高,所有的缓存机制看到 cache-control 都要服从它

缓存:设置max-age在这个时间内都不进行http请求,从缓存中读取

cache-control描述
no-store请求和相应都不缓存
no-cache协商缓存,相当于cache-control:max-age=0
max-age指定多少秒后资源过期(强缓存
  • expires

这个是为了兼容http1.0,由于客户端可以修改时间,所以,expires优先级低,缓存策略以cache-control为准

2. 协商缓存

在第一次请求服务器时,服务器会返回资源,并且返回一个资源的缓存标识,一起存到浏览器的缓存数据库。当第二次请求资源时,浏览器会首先将缓存标识发送给服务器,服务器拿到标识后判断标识是否匹配,如果不匹配,表示资源有更新,服务器会将新数据和新的缓存标识一起返回到浏览器;如果缓存标识匹配,表示资源没有更新,并且返回 304 状态码,浏览器就读取本地缓存服务器中的数据。

涉及到的状态码:

  • 304 not modified
  • 200 ok

涉及到的请求头

  • last-modified (响应头)/ if-modified-since(请求头)

当浏览器第一次请求时,服务端返回资源的同时,会在响应头中添加last-modified,表示资源的最后修改时间,浏览器在第二次请求这个url时会在请求头中带上if-modified-since请求头,值为上一次请求的last-modified,用来询问该文件是否被修改过。

但是last-modified时间只能精确到秒,且无法识别出内容没有修改过的文件,只要修改时间变了就算变动,因此有了etag

  • etag(响应头) / ig-none-match(请求头)

etag解决了last-modified的问题,当etag和last-modified同时存在时则以etag为准

nginx的etag计算方式:计算页面文件的最后修改时间,将文件最后修改时间的秒级Unix时间戳转为16进制作为etag的第一部分 计算页面文件的大小,将大小字节数转为16进制作为etag的第二部分。

etag两种类型:

强etag:

不论实体发生多么细微的变化都会改变其值

强ETag表示形式:"22FAA065-2664-4197-9C5E-C92EA03D0A16"

弱etag:

弱 ETag 值只用于提示资源是否相同。只有资源发生了根本改变产 生差异时才会改变 ETag 。这时,会在字段值最开始处附加 W/

弱ETag表现形式:W/"22FAA065-2664-4197-9C5E-C92EA03D0A16"

浏览器第二次请求上次请求过的url时,浏览器会在HTTP请求头添加一个If-None-Match的标记,用来询问服务器该文件有没有被修改。

四、项目遇到的问题

  • 项目上线后用户需手动刷新页面才能获取新的资源

产生原因:http请求没有设置缓存机制(cache-control或者expires),导致浏览器不知道以什么方式缓存。这种情况一般默认为强缓存,强缓存时间根据一定的计算方式获得,在这个时间段内不会进行网络请求,返回的状态码为200(from disk cache)或者200(from memory cache)

解决办法:

 针对不能加hash值又想要随时获取最新资源的html文件,应该设置请求头 cache-control:no-cache,相当于cache-control:max-age=0

  • 奇怪的问题与排查

现象:nginx并没有配置cache-control或者expires,但是有时却不需要刷新就可以返回最新的资源(200 ok),而有时则返回200 from disk cache。

排查:

查看http的header信息,发现差别在if-modified-sine这个请求头上,返回200 ok的请求头会携带if-modified-sine,而返回200 from disk cache的请起头中没有携带if-modified-sine。

查了一些资料终于找到原因,原因如下:

if-modified-sine的值是第一次报文中 last-modified 的值

为什么会有条件请求字段呢?是因为缓存过期了,所以浏览器会从缓存中查找是否有etag、last-modified字段(注意,缓存缓存的整个报文,而不仅仅是body部分),有的话,就在请求中带上,向服务器发起协商缓存请求。如果服务器发现资源没有改变,就返回304响应,浏览器就知道,本地缓存中的这个数据资源可以继续使用。(304响应是没有body体的,只有头字段等元信息)也就是说,只有在缓存过期的情况下,请求报文中才会有条件请求的相关字段。什么情况下,缓存会过期呢?如下:

  1. cache-control: max-age=0
  2. cache-control: no-cache
  3. 响应报文根本就没有返回任何关于cache有效期的头字段: cache-control / expire / progma 。那么看是否返回了 last-modified ,如果有该header,浏览器可以使用 Heuristic 算法计算出一个通用的缓存时间 (Date - last-modified) * 10% 

第三点原因就是项目中遇到的奇怪现象的解释。

文章借鉴:https://segmentfault.com/q/1010000007008829     浏览器缓存带来的前端项目更新问题及解决方法_浏览器缓存的数据,如果服务器的数据有变化怎么办-CSDN博客


http://www.ppmy.cn/ops/145102.html

相关文章

【汇编】关于函数调用过程的若干问题

1. 为什么需要bp指针? 因为bp是栈帧的起始地址,函数内的局部栈变量,采用相对bp的内存寻址。不能相对于sp,sp是一直在变的。 2. 函数调用过程? 函数开始,先压栈bp,保存父函数栈底指针bp&#…

[Router]路由器常用的后台判断网络ping 可靠公共 IP 地址整理

接受ICMP公共DNS地址 接受 ICMP 的公有 IPv4 和 IPv6 端点的集合,如果使用 ping 方法,则可以使用来跟踪接口的连接状态。这些是具有高可用性的,通常可以可靠地用作确认网络连接的终端节点。或者,您也可以使用 ISP 的 DNS 解析器&a…

C语言结构体位定义(位段)的实际作用深入分析

1、结构体位段格式 struct struct_name {type [member_name] : width; };一般定义结构体,成员都是int、char等类型,占用的空间大小是固定的在成员名称后用冒号来指定位宽,可以指定每个成员所占用空间,并且也不用受结构体成员起始…

Django 模型字段类型详解

在 Django 中,模型是应用程序的核心部分之一。它们是 Python 对象,用于映射数据库表。每个模型都由一系列字段组成,这些字段代表数据库表中的列。Django 提供了丰富的字段类型,用于定义模型字段,以满足各种数据存储需求。 © ivwdcwso (ID: u012172506) 1. CharField Cha…

基于小程序宿舍报修系统的设计与实现ssm+论文源码调试讲解

第2章 开发环境与技术 基于微信小程序的宿舍报修系统的编码实现需要搭建一定的环境和使用相应的技术,接下来的内容就是对基于微信小程序的宿舍报修系统用到的技术和工具进行介绍。 2.1 MYSQL数据库 本课题所开发的应用程序在数据操作方面是不可预知的,…

周期性边界条件、近邻列表和原子间作用势

文章目录 1.周期性边界条件1.什么是周期性边界条件(PBC)2.周期性边界条件基本特点3.最小镜像约定4.Python实现 2.势场的有限距离截断1.原子间相互作用力2.势场截断的理论基础3.势场截断方法 3.近邻列表构筑与更新1.近邻算法:VerletList法2.近邻算法:区间…

Hive其四,Hive的数据导出,案例展示,表类型介绍

目录 一、Hive的数据导出 1)导出数据到本地目录 2)导出到hdfs的目录下 3)直接将结果导出到本地文件中 二、一个案例 三、表类型 1、表类型介绍 2、内部表和外部表转换 3、两种表的区别 4、练习 一、Hive的数据导出 数据导出的分类&…

【C++】初识C++之C语言加入光荣的进化(上)

写在前面 本篇笔记作为C的开篇笔记,主要是讲解C关键字(C98)连带一点点(C11)的知识。掌握的C新语法新特性,当然C是兼容C的,我们学习C的那套在C中也是受用。 文章目录 写在前面一、命名空间域1.1、命名空间域的定义与使用1.2、命名空间域的细节…