浏览器http缓存问题

一、什么是浏览器缓存

浏览器将请求过的资源(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)请求了服务器,但是由于服务器资源没有更新,所以仍使用内存中的资源

二、缓存机制介绍

1. 强缓存

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

涉及到的状态码:

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

涉及到的http header: 

  • cache-control
  • expires

2. 协商缓存

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

涉及到的状态码:

  • 304 not modified
  • 200 ok

涉及到的请求头

  • etag / ig-none-match
  • last-modified / if-modified-since

三、缓存相关的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;缓存的服务器资源的唯一标识
  • cache-control

优先级最高,所有的缓存机制看到 cache-control 都要服从它;在请求头和响应头中都可以设置;cache-control有多种设置,设置如下:

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

 

  • expires

http 1.0的字段,它定义的时间是相对于服务器的时间,但是如果客户端和服务器端的时间可能不一致,而且用户可以修改客户端的时间,所以expires时间不准确,以cache-control为准

  • last-modified

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

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

 

  • etag

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     https://blog.csdn.net/feiyu_may/article/details/88376945

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值