Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Http缓存 #28

Open
Genluo opened this issue Aug 31, 2019 · 0 comments
Open

Http缓存 #28

Genluo opened this issue Aug 31, 2019 · 0 comments

Comments

@Genluo
Copy link
Owner

Genluo commented Aug 31, 2019

缓存是一个比较大的知识点,同时也是一个极大提高性能的点,缓存有很多种,常见的有浏览器缓存、服务器缓存、代理服务器缓存、CDN缓存

首先谈下浏览器中的两种缓存策略,强缓存和协商缓存

  • 强缓存是在加载资源的时候,根据请求头部的expirescache-control判断是否命中缓存,是则直接从缓存中读取资源,不会发送请求到服务器

  • 如果没有命中强缓存,浏览器一定会发送一个请求到服务器,通过last-modifiedetag验证资源是否命中协商缓存,如果命中,服务器会发送304响应给浏览器,浏览器根据返回的报文更新缓存中的数据,但是不会返回这个资源的数据,依然是从缓存中读取资源

    如果协商缓存没有命中,则直接返回给客户端新的数据

1、强缓存

1)Expires

这是http1.0中提到的一个表示过期时间的Header,他描述的是一个绝对时间,由服务器返回,这个字段受限于本地时间,如果本地时间,可能造成缓存失效,目前H5中也可以通过meta标签来给页面设置缓存<meta http-equiv="Expires" content="Thu, 01 Dec 1994 16:00:00"/>

2)Cahce-Control

  • max-age浏览器会第一期请求的时候设置的资源有效期,这是一个相对的值,后面浏览器在请求资源的时候,会根据此时的值来计算出一个资源过期时间,然后通过这个时间进行强缓存判断

  • no-cache浏览器会缓存到本地,但是每次请求数据都需要从源服务器中请求进行协商缓存

  • no-store才是真正的不存储数据到本地

  • public可以被多用户缓存(终端、CDN中间服务器)

  • private只能被终端浏览器缓存(私有缓存),不允许中继缓存服务器进行缓存

2、协商缓存

当协商缓存命中,请求响应返回的Http状态是304并且显示一个Not Modified的字符,协商缓存主要使用西下面这几个字段来进行控制

1)Last-Modified、If-Modified-Since

Last-Modified表示本地文件最后修改日期,浏览器会在请求头部加上If-Modified-Since(上次返回的Last-Modified),询问服务器在该日期后资源是否有更新,有更新的话会将新的资源发送回来

如果本地打开缓存文件,就会造成Last-Modified被修改,所以在Http/1.1出现了Etag

2)ETag、If-None-Match

ETag就是一个hash,资源内容的变化都会导致Etag变化,跟最后修改时间没有关系,ETag可以保证每一个资源是唯一的

If-None-Match的header会将上次返回的Etag发送给服务器,询问该资源的ETag是否有更新,有变动就会发送新的资源回来

Etag的优先级比Last-Modified更高

具体为什么要使用Etag,主要出于下面几种情况的考虑:

  • 一些文件被周期性的更改,但是他的内容并不会发生改变(仅仅改变修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而要重新GET
  • 某些文件修改非常频繁,比如在秒以下的时间内进行更改,但是If-Modified-Since能检查到的粒度是s级的,所以这种修改无法判断(或者说unix记录MIIME只能精确到秒)
  • 某些服务器不能精确的得到文件的最后修改时间

3、状态码的区别

  • 200:目前两种缓存读取方式,一种是磁盘缓存(from disk cache)、一种是内存缓存(from memory cache)两种,
  • 304:(Not Modify): 协商缓存Last-modified/Etag没有过期时,服务器返回状态吗304

4、选择缓存的时候需要注意

  • 分布式系统里多台机器见文件的Last-Modified必须保持一致,以免负载均衡到不同机器导致比对失败
  • 分布式系统尽量关闭掉Etag(每台机器生成的Etag都会不一样),或者保证每台机器生成的Etag是一样的
    头部 | 优势和特点 | 劣势和问题
    -- | -- | --
    Expires | 1、HTTP 1.0 产物,可以在HTTP 1.0和1.1中使用,简单易用。 2、以时刻标识失效时间。 | 1、时间是由服务器发送的(UTC),如果服务器时间和客户端时间存在不一致,可能会出现问题。 2、存在版本问题,到期之前的修改客户端是不可知的
    Cache-Control | 1、HTTP 1.1 产物,以时间间隔标识失效时间,解决了Expires服务器和客户端相对时间的问题。 2、比Expires多了很多选项设置。 | 1、HTTP 1.1 才有的内容,不适用于HTTP 1.0 。 2、存在版本问题,到期之前的修改客户端是不可知的。
    Last-Modified | 1、不存在版本问题,每次请求都会去服务器进行校验。服务器对比最后修改时间如果相同则返回304,不同返回200以及资源内容。 | 1、只要资源修改,无论内容是否发生实质性的变化,都会将该资源返回客户端。例如周期性重写,这种情况下该资源包含的数据实际上一样的。 2、以时刻作为标识,无法识别一秒内进行多次修改的情况。 3、某些服务器不能精确的得到文件的最后修改时间。
    ETag | 1、可以更加精确的判断资源是否被修改,可以识别一秒内多次修改的情况。 2、不存在版本问题,每次请求都回去服务器进行校验。 | 1、计算ETag值需要性能损耗。 2、分布式服务器存储的情况下,计算ETag的算法如果不一样,会导致浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时发现ETag不匹配的情况。
头部 优势和特点 劣势和问题
Expires 1、HTTP 1.0 产物,可以在HTTP 1.0和1.1中使用,简单易用。 2、以时刻标识失效时间。 1、时间是由服务器发送的(UTC),如果服务器时间和客户端时间存在不一致,可能会出现问题。 2、存在版本问题,到期之前的修改客户端是不可知的
Cache-Control 1、HTTP 1.1 产物,以时间间隔标识失效时间,解决了Expires服务器和客户端相对时间的问题。 2、比Expires多了很多选项设置。 1、HTTP 1.1 才有的内容,不适用于HTTP 1.0 。 2、存在版本问题,到期之前的修改客户端是不可知的。
Last-Modified 1、不存在版本问题,每次请求都会去服务器进行校验。服务器对比最后修改时间如果相同则返回304,不同返回200以及资源内容。 1、只要资源修改,无论内容是否发生实质性的变化,都会将该资源返回客户端。例如周期性重写,这种情况下该资源包含的数据实际上一样的。 2、以时刻作为标识,无法识别一秒内进行多次修改的情况。 3、某些服务器不能精确的得到文件的最后修改时间。
ETag 1、可以更加精确的判断资源是否被修改,可以识别一秒内多次修改的情况。 2、不存在版本问题,每次请求都回去服务器进行校验。 1、计算ETag值需要性能损耗。 2、分布式服务器存储的情况下,计算ETag的算法如果不一样,会导致浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时发现ETag不匹配的情况。
头部 优势和特点 劣势和问题
Expires 1、HTTP 1.0 产物,可以在HTTP 1.0和1.1中使用,简单易用。 2、以时刻标识失效时间。 1、时间是由服务器发送的(UTC),如果服务器时间和客户端时间存在不一致,可能会出现问题。 2、存在版本问题,到期之前的修改客户端是不可知的
Cache-Control 1、HTTP 1.1 产物,以时间间隔标识失效时间,解决了Expires服务器和客户端相对时间的问题。 2、比Expires多了很多选项设置。 1、HTTP 1.1 才有的内容,不适用于HTTP 1.0 。 2、存在版本问题,到期之前的修改客户端是不可知的。
Last-Modified 1、不存在版本问题,每次请求都会去服务器进行校验。服务器对比最后修改时间如果相同则返回304,不同返回200以及资源内容。 1、只要资源修改,无论内容是否发生实质性的变化,都会将该资源返回客户端。例如周期性重写,这种情况下该资源包含的数据实际上一样的。 2、以时刻作为标识,无法识别一秒内进行多次修改的情况。 3、某些服务器不能精确的得到文件的最后修改时间。
ETag 1、可以更加精确的判断资源是否被修改,可以识别一秒内多次修改的情况。 2、不存在版本问题,每次请求都回去服务器进行校验。 1、计算ETag值需要性能损耗。 2、分布式服务器存储的情况下,计算ETag的算法如果不一样,会导致浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时发现ETag不匹配的情况。

5、用户刷新/访问行为

1、在URL输入栏中输入然后回车

浏览器会针对文件进行缓存,直到该文件过期、用户清空cache或者用户强制刷新资源时间

2、F5/点击工具栏中的刷新按钮/右键菜单重新加载

每个资源都需要进行协商缓存,忽略强缓存的相关字段。

3、ctrl+F5

彻底从服务器,拿到一份新的资源过来,所以不光要发送请求给server,而且这个请求要将所有协商缓存控制头去掉,这种的操作全部返回的是200,并刷新了相关缓存的控制时间

实际上保证为了拿到是从服务器上最新的代码,还需要添加一些HTTP Headers,按照Http/1.1协议,Cache不仅仅是存在于浏览器端,从浏览器到Server的中间节点也可能扮演者Cache的作用,为了防止获得的只是这些中间节点的Cahche,需要告诉他们,别用自己的缓存的数据来敷衍我,往Upstream节点要一个最新的copy

Cache-Control: no-cache
Pragma: no-cache

6、如何判断文件来源

这里我们需要知道另外两个头部,一个是Date,另一个是Age字段来得到答案。

Date 理所当然是源服务器发送该资源响应报文的时间(GMT格式),如果你发现 Date 的时间与“当前时间”差别较大,或者连续F5刷新发现 Date 的值都没变化,则说明你当前请求是命中了代理服务器的缓存。

Age是响应报文中的首部字段,他表示该文件在代理服务器中存在的时间,如文件被修改或者替换,Age会重新从0开始累计。

7、浏览器如何进行强缓存

首先明确浏览器会存在两个字段,一个Expires(一个绝对时间),Max-age指的是从文档被访问后的存活时间,这个时间是相对时间,相对于文档被第一次请求的Request_time(请求时间),在Apache中,max-age是根据Expires的时间来计算出来的max-age = expires- request_time:(mod_expires.c),因为Expires中的时间是根据服务器端的时间来生成的,这样的话就存在一个问题,如果本地时间和服务器端时间相差很大的话就会产生很大的误差,Expries = Max-age + requestz_time,我们其实根据Date字段和Expires字段和Max-age和Age字段来计算目前是否进行强缓存

8、字段优先级问题

根据上面的分析我们可以知道,缓存的优先级是Cache-Control > Expires > ETag > Last-Modified

9、s-maxage字段

这个字段是设置中间服务器的缓存时间,想象这样一种情况,我们设置max-age为一年,但是如果代理服务器上也遵守这样的缓存策略,那么代理也需要将资源缓存一年,这种就是在浪费代理服务器的资源,所以为了保证代理服务器有不一样的缓存策略,我们使用s-maxage来处理代理服务器的相关缓存设置,针对代理服务器会优先考虑s-maxage,这样我们才可以对代理服务器设置不同的缓存策略。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant