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缓存 #1

Open
ahaow opened this issue Apr 22, 2022 · 1 comment
Open

http缓存 #1

ahaow opened this issue Apr 22, 2022 · 1 comment

Comments

@ahaow
Copy link
Owner

ahaow commented Apr 22, 2022

http 缓存

http缓存是浏览器在本地磁盘对用户最近请求的文档进行存储,当访问者再次访问同一个页面的时候,浏览器就可以直接从本地磁盘加载文档

其优点有:

  1. 减少冗余的数据传输
  2. 减少服务器负担
  3. 加快客户端加载网页的速度

浏览器缓存是Web性能优化的重要方式。那么浏览器缓存的过程究竟是怎么样的呢?

在浏览器第一次发起请求时,本地无缓存,向web服务器发送请求,服务器响应请求,浏览器缓存

LBQ1q1.png

  1. 第一个请求时,服务器会将页面最后修改的时间通过Last-modified标识由服务器发送给客户端,客户端记录修改时间
  2. 服务器还会生成一个Etag,发送给客户端

浏览器后续再次进行请求时:

LBGA4P.png

浏览器缓存主要分为:

  1. 强缓存(本地缓存)
  2. 协商缓存(弱缓存)

根据上图,再次发送请求时:

  1. 浏览器请求某一个资源时,会先获取该资源缓存的header信息,根据header里面的Cache-controlExpires 来判断是否过期,

  2. 若没过期,则直接从缓存中获取相关信息,包括缓存的header信息,所以此次不会与服务器进行通信;这里判断过期,是强缓存相关

  3. 若过期了,浏览器则会向服务器发送请求,这个请求会携带第一次请求返回的有关缓存的header字段信息

    1. 客户端会通过请求头If-None-Match将先前服务器端发送过来的Etag发送给服务器,服务器会对比这个客户端发过来的Etag是否与服务器相同,
    2. 若相同,就将If-None-match的值设置为false,返回状态304,客户端继续使用本地缓存,不解析服务器端发过来的数据

    LBNNJ1.png

    1. 若不相同,就将If-None-match的值设置为true,客户端重新解析服务器返回的数据;
    2. 客户端还会通过If-Modified-Since头将之前服务器发送过来的最后修改的时间戳给服务器,服务器端通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的,则返回最新的内容,若是新的,则返回304,客户端继续使用本地缓存

@ahaow
Copy link
Owner Author

ahaow commented Apr 22, 2022

强缓存

强缓存就是利用http头中的ExpiresCache-Control两个字段来控制的,用来表示资源的缓存时间

强缓存中,普通刷新会忽略,但不会清除它,需要强制刷新,浏览器强制刷新,请求会带上Cache-Control: no-cachePargma: no-cache

Expires

Expireshttp1.0的规范,它的值是一个绝对时间的GMT格式的时间字符串

例如现在这个网页的expires: Wed, 20 Apr 2022 01:33:40 GMT ,这个时间代表这个资源的失效时间,只要发送请求时间是在Expires之前,那么本地缓存始终有效,则会在本地缓存中读取数据

所以这种方式有一个明显的缺点:由于失效的时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱

如果同时出现Cache-control:max-ageExpires,那么max-age优先级更高

cache-control: max-age=3600 // 表示资源可以被缓存的最长时间为3600s, 会优先考虑max-age
expires: Wed, 20 Apr 2022 01:33:40 GMT

Cache-Control

Cache-Control是在http1.1中出现的,主要是利用该字段的max-age值来判断,它是一个相对时间

例如Cache-Control: max-age=3600, 代表资源的有效期在3600秒

Cache-Control的常用值

  1. max-age=3600:

    1. public: 客户端和代理服务器都可以缓存该资源, 客户端在3600s有效期之内,有请求该资源,直接读取缓存,status: 200
    2. private : 只让客户端可以缓存该资源;代理服务器不缓存,客户端在xxx秒内直接读取缓存,statu code:200
    3. immutable: 客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,即使用户做了刷新操作,也不向服务器发起http请求
  2. no-cache: 不使用本地缓存,需要使用协商缓存,先与服务器确认返回的响应是否被更改,如果之前的响应存在ETag, 那么请求的时候会与服务端验证,如果资源没有被更改,则无需重新下载

  3. no-store: 直接禁止浏览器缓存数据,每次请求数据,都会向服务器发送一个请求,都会下载完整的资源

Cache-ControlExpires 可以在服务端配置同时启动,Cache-Control的优先级更高

协商缓存

协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务端要通过某种标识来进行通信,从而让服务器判断请求资源是否可用缓存

普通刷新会启用协商缓存, 忽略强缓存,只有在地址栏或收藏夹输入网址、通过链接引用资源等情况下,浏览器才会启用强缓存,这也是为什么有时候我们更新一张图片、一个js文件,页面内容依然是旧的,但是直接浏览器访问那个图片或文件,看到的内容却是新的

这个主要涉及到两组header字段:EtagIf-None-MatchLast-ModifiedIf-Modified-Since

Etag 和 If-None-Match

ETagResponse Headers

If-None-MatchRequest Headers

EtagIf-None-Match 返回的是一个校验码,Etag可用保证每一个资源都是唯一的,资源变化都会导致Etag变化, 服务器根据浏览器上的If-None-Match值来判断是否命中缓存

Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于Etag重新生成过, Response Header还是会把这个Etag返回,即使这个Etag并没有改变

Last-Modified / If-Modified-Since

浏览器第一次请求一个资源的时候,服务器返回的header会加上Last-ModifiedLast-modified是一个时间标识,表示该资源的最后修改时间

LrKpFK.png

浏览器再次请求资源时,Request Headers请求头里面会包含一个If-Modified-Slice, 该值为缓存之前返回的Last-Modified。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。

若命中缓存,则返回304, 并不会返回资源内容,并且不会返回Last-Modified

若没有命中缓存,返回200,返回最新的资源

LrKsmR.png

LrMPA0.png

为什么要有ETag

你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?

HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

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

Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

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

No branches or pull requests

1 participant