美文网首页
来看看 HTTP 缓存?

来看看 HTTP 缓存?

作者: 猪哥闲聊 | 来源:发表于2020-03-06 17:07 被阅读0次

    废话

    最近在家不用上班,有点无聊,打了几天游戏,感觉好空虚,还是看点东西学习吧。看到了 HTTP 缓存,之前有看过一点,今天大概整理一下。

    作用

    重用资源,提高网站和应用的性能。减少网络延迟带来的影响,提升用户体验。一般用于 Get 请求。

    缓存的类型

    1. 不缓存

    不使用缓存

    2.(私有)浏览器缓存

    用于单独用户,提供前进后退、保存网页的功能

    3.(共享)代理缓存

    可用于多个用户,比如大型公司都会架设一个 Web代理器,代理服务器可以提供代理缓存功能给用户使用。热门的资源可以被复用,减少网络拥堵。

    缓存的控制

    Cache-Control

    用来定义缓存的策略,请求头和响应头都支持。

    禁止缓存

    缓存中不得存储任何 客户端请求 和 服务器响应 的内容。

    Cache-Control: no-store

    强制确认缓存

    Cache-Control: no-cache

    上面这个头信息,并不是说不缓存,而是说每次都要服务器确认缓存是否可用。使用了这个头信息,每次请求还是会发给服务器,如果服务器返回 304 ,则说明可以继续使用缓存,如果是其他则不使用缓存。

    私有缓存 和 公共缓存

    Cache-Control: private

    默认的配置,表示缓存只属于某个用户,中间人(中间人指中间代理,CDN等)不应该存储。

    Cache-Control: public

    表示该信息可以被任何中间人缓存

    缓存过期机制

    Cache-Control: max-age=31536000

    最常用的就是 max-age=xxxxxx 了,单位是秒,表示缓存距离上次请求之后能用多久,也就是新鲜度。

    Expires: Wed, 21 Oct 2015 07:28:00 GMT

    max-age 相近的是 Expires ,但是 Expires 表示的是一个具体过期时间。

    Pragma

    HTTP 1.0 定义的 header ,之前没有明确定义,功能上又和 Cache-Control 重合,没什么用,废弃

    Pragma 是HTTP/1.0标准中定义的一个header属性,请求中包含Pragma的效果跟在头信息中定义Cache-Control: no-cache相同,但是HTTP的响应头没有明确定义这个属性,所以它不能拿来完全替代HTTP/1.1中定义的Cache-control头。通常定义Pragma以向后兼容基于HTTP/1.0的客户端。

    新鲜度

    说到缓存,肯定不能缓存所有的资源,所以就会有一套算法来做 缓存驱逐 ,这个算法就是 驱逐算法。对应的有资源过期了,就会有新的资源更新缓存,以此来保持本地缓存的新鲜度。

    当然,一个资源是不是过期了,有些时候不是本地缓冲器一个人说了算,还要跟服务器商量。我们就要分成两种情况了。

    强制缓存

    Cache-Control: max-age=31536000
    Expires: Wed, 21 Oct 2015 07:28:00 GMT
    

    以上两种缓存,刚才已经说过了,就不多说了。如果服务器返回的响应头中有这两个头信息,而且没过期,就可以直接使用本地缓存了。

    协商缓存

    这种情况下,一个资源是不是过期要跟服务器商量,也是比较复杂的情况。我们先对几个相关的响应头说明一下。

    ETag

    响应头,相当是对一个资源做了唯一标识,可以更加准确判断一个资源是否进行更新。还可以有助于防止资源同时更新导致互相覆盖的问题(空中碰撞)。一般是使用资源的 Hash 。

    格式如下:

    ETag: "<etag_value>"
    
    ETag: W/"<etag_value>"
    

    W/ 表示 弱验证器(Weak validation),对大小写不敏感。

    If-None-Match 和 If-Match

    这两个都是请求的头信息,表示一个条件请求。所传的值是 ETag 。

    If-None-Match

    If-None-Match: <etag_value>
    
    If-None-Match: <etag_value>, <etag_value>, …
    
    If-None-Match: *
    

    If-None-Match 表示的是请求资源 ETag 跟这个 ETag 不同服务器就返回更新后资源。

    但是如果请求的资源 的 ETag 跟这个相同,则返回 304 ,表示资源没有变更,可以继续使用旧的缓存,并且头部中还可能会添加 Cache-Control、Content-Location、Date、ETag、Expires 等头信息,用来更新新鲜值。

    If-Match

    If-Match: <etag_value>
    
    If-Match: <etag_value>, <etag_value>, …
    
    If-Match: *
    

    这个更缓存的关系并不是很大,但是容易跟 If-None-Match 混淆,这里也说一下。If-Match 表示如果请求的资源 ETag 跟这个 ETag 相同才会返回资源。一般有下面的两种用途:

    1. 对于 GET 和 HEAD ,搭配 Range 头信息来使用,保证新请求的范围和之前请求的范围是同一份。如果不同则服务器需返回 416。看到官方这个场景的描述,我也是一脸懵逼,没想到具体的使用场景。
    2. 对于 POST ,可以用来防止更新丢失的问题,也就是之前说的“空中碰撞”的问题。比如两个人都对同一份文件进行修改,提交的时候使用这个请求头,肯定有一个人的更新会冲突,就像 Git 提交一样,因为两个人的请求头中 If-Match 的值都是最原始那个文件,慢提交的人就跟服务器上的 Etag 不同了,也就会提交不上,报冲突了。如果冲突了,服务器返回的是 412 。

    Last-Modified 和 If-Modified-Since

    Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT 
    
    If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT 
    

    这两个是一对配合使用的,Last-Modified 是响应头的头信息,返回资源的最后更新时间,IF-Modified-Since 是请求头的头信息,表示如果资源在这个时间之后有更新,则返回资源,如果没更新则返回 304。

    缓存处理流程

    客户端第一次发请求的时候,服务器可能会返回 Connection-Control 、Expires 、ETag 、Last-Modified 等多个响应头来做缓存操作。

    客户端第二次发请求的时候,如果上次响应中有 Connection-Control 、Expires 这两个响应头,客户端可以根据这个两个时间来判断资源是否过期,如果还没过期,就继续使用缓存,如果过期则重新向服务器发请求。

    在重新向服务器发请求的时候,也会带上上次响应跟缓存控制有关的响应头。

    比如 上次响应头有 ETag ,这次请求就会在请求头中加上 If-None-Match 并附上 ETag 的值。如果上次响应中有 last-Modified ,这次请求中就会在请求头中加上 If-Modified-Since 并附上 Last-Modified 的值。

    当然这个时候,缓存过没过期就跟客户端没关系了,反正都塞给服务器,让服务器去做判断。

    这几个响应头到了服务器后,服务器就要开始判断请求的这个资源是不是过期了。因为 ETag 比 Last-Modified 更准确(有时候会只修改更新时间,而不修改文件),所以首先判断的是 If-None—Match ,如果同时出现 If-None-Match 和 If-Modified-Since ,则 If-Modified-Since 会被忽略。

    如果 If-None-Match 跟服务器上资源的 ETag 不同,就返回更新后的资源,如果相同,则返回 304 并不返回响应体,告诉客户端,这个资源还没过期,可以继续使用,并且响应头中可能会重新加入 Connection-Control 、Expires 、ETag 、Last-Modified 等用来更新客户端缓存的新鲜值。

    如果发到服务器中的请求头中,没有 If-None-Match 只有 If-Modified-Since ,则根据服务器上该资源最后的更新时间是否大于 If-Modified-Since 的时间,如果大于,则返回新的资源,如果相同,则跟 If-None-Match 一样返回 304

    如果请求中什么跟缓存控制相关的请求头,都没有的话,这就相当于第一次请求了,直接返回资源就可以了。

    最后附上一张图示:

    HTTP缓存图示

    相关文章

      网友评论

          本文标题:来看看 HTTP 缓存?

          本文链接:https://www.haomeiwen.com/subject/jwdwrhtx.html