status code: 200 OK (FROM CACHE) 与 304 NOT MODIFIED

前几天同事给我演示304的时候,控制台网络信息都是200(from cache),下来我深入研究了一下:

1.200 OK (FROM CACHE) 与 304 NOT MODIFIED均使用本地缓存资源。

2.200 OK (FROM CACHE)未进行http请求,304 NOT MODIFIED为发送服务器请求后得到的状态码。


目录

本地缓存阶段 Expires/Cache-Control

协商缓存阶段 Last-Modified/ETag

缓存失败阶段

总结


web 缓存

在一个Web应用中,应用到缓存的地方有很多,浏览器缓存,页面缓存,服务器缓存,数据库缓存等。

缓存的作用主要有:

  • 加快页面打开速度
  • 减少网络带宽消耗
  • 降低服务器压力

缓存行为主要由缓存策略决定,而缓存策略由内容拥有者设置。这些策略主要通过特定的HTTP头部表达。即开放资源的服务器根据自身缓存策略定义相应的http头部字段,收到response的浏览器根据response.header中的特定字段进行相应处理。

当一个用户发起一个静态资源请求的时候,浏览器会通过以下几步来获取资源:

  • 本地缓存阶段:先在本地查找该资源,如果有发现该资源,而且该资源还没有过期,就使用这一个资源,完全不会发送http请求到服务器;
  • 协商缓存阶段:如果在本地缓存找到对应的资源,但是不知道该资源是否过期或者已经过期,则发一个http请求到服务器,然后服务器判断这个请求,如果请求的资源在服务器上没有改动过,则返回304,让浏览器使用本地找到的那个资源;
  • 缓存失败阶段:当服务器发现请求的资源已经修改过,或者这是一个新的请求(在本来没有找到资源),服务器则返回该资源的数据,并且返回200, 当然这个是指找到资源的情况下,如果服务器上没有这个资源,则返回404。

本地缓存阶段 Expires/Cache-Control

Expires

 Expires 头部字段指定缓存到期GMT的绝对时间。如果expires到期需要重新请求,在该日期前的所有对该资源的请求都会直接使用浏览器缓存而不用向服务器请求。

浏览器请求某网页,打开Chrome控制台查看某资源的Response Headers(需要选取可缓存资源,可控制台中ctrl+f搜索Expires):

      
  但是使用Expires存在服务器端时间和浏览器时间不一致的问题。

Cache-Control

Cache-Control是http 1.1中为了弥补 Expires 缺陷新加入的。对已缓存的内容进行控制, 允许源服务器覆盖一个响应默认的缓存功能,简单地说,该字段用于控制浏览器在什么情况下直接使用本地缓存而不向服务器发送请求:

  • Cache-control: public表示缓存的版本可以被代理服务器或者其他中间服务器识别。
  • Cache-control: private意味着这个文件对不同的用户是不同的。只有用户自己的浏览器能够进行缓存,公共的代理服务器不允许缓存。
  • Cache-control: no-cache意味着文件的内容不应当被缓存。这在搜索或者翻页结果中非常有用,因为同样的URL,对应的内容会发生变化。

其他相关控制字段

  • max-age: 指定缓存过期的相对时间秒数,max-ag=0或者是负值,浏览器会在对应的缓存中把Expires设置为1970-01-01 08:00:00。
  • s-maxage: 类似于max-age,只用在共享缓存上,比如proxy。
  • public: 通常情况下需要http身份验证的情况,响应是不可cahce的,加上public可以使它被cache。
  • no-cache: 强制浏览器在使用cache拷贝之前先提交一个http请求到源服务器进行确认。这对身份验证来说是非常有用的,能比较好的遵守 (可以结合public进行考虑)。它对维持一个资源总是最新的也很有用,与此同时还不完全丧失cache带来的好处),因为它在本地是有拷贝的,但是在用之前都进行了确认,这样http请求并未减少,但可能会减少一个响应体。
  • no-store: 告诉浏览器在任何情况下都不要进行cache,不在本地保留拷贝。
  • must-revalidate: 强制浏览器严格遵守你设置的cache规则。
  • proxy-revalidate: 强制proxy严格遵守你设置的cache规则。
  • cache:使用本地缓存,不发生请求。

示例:

缓存过期的相对时间为300秒,若300s内再次需要页面资源,不发送http请求,直接调用本地资源。

Cache-control值为“no-cache”时,访问此页面不会在Internet临时文章夹留下页面备份

注意:cache-control max-age 和 s-maxage 将覆盖 Expires 头部。即以 max-age 为判断。

此时状态码200 OK (from cache),  浏览器没有跟服务器确认,直接用了浏览器缓存。


协商缓存阶段 Last-Modified/ETag

Last-Modified :

服务器端当允许某资源使用缓存时,需要设置response头以下字段:

            response.Clear();
            response.ClearContent();
            response.Headers["Last-Modified"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            response.Headers["ETag"] = id;//这里假设的是根据不同的id
            response.CacheControl = "private";

Last-Modified :服务器端上次修改该文件的时间。

ETag:ensure tag,这个下文再说。

浏览器请求某网页,打开Chrome控制台查看某资源的Response Headers(需要选取可缓存资源,可控制台中ctrl+f搜索Last-Modified):

客户端再次请求该资源的时候,发现自己缓存中有该资源,那么在请求中会包含If-Modified-Since ,这个If-Modified-Since 的值就是缓存文件的 Last Modified

再次请求该资源时request headers中有If-Modified-Since字段:

注:同一文件response的Last-Modified与再次request该资源的If-Modified-Since值相同,此处不同因为我截取报文的资源不同。

服务器端根据请求的request.headers中相应字段的值,判断浏览器端上送的If-Modified-Since与服务器端该资源的Last-Modified 是否相等,是则返回304,让浏览器使用缓存资源,否则返回status 200,重新发送该资源并返回新的资源最后修改时间Last-Modified

判断是否返回资源,服务器端代码示意:

var request = context.Request;
            var response = context.Response;
            if (request.Headers["If-Modified-Since"].NotNullOrEmpty() || request.Headers["If-None-Match"].NotNullOrEmpty())
            {
                response.StatusCode = 304;
                return;
            }
//非304情况下的操作 略

这段代码其实不准确,判断了request.Header存在If-Modified-Since或者If-None-Match即返回304,准确应该是判别If-Modified-SinceIf-None-Match均通过才返回304,否则重新获取资源返回200(资源可获取的情况下)。在返回 304 的时候已经做了一次数据库查询,但避免了接下来更多的数据库查询,并且没有返回请求内容只返回一个 HTTP Header,从而降低带宽的消耗。

我们可以看到这里除了If-Modified-Since还判断了If-None-Match,要了解什么是If-None-Match,我们先介绍一下上文的E-tag。

E-tag

E-tagLast-Modified的补充

Last-Modified本身有缺点,以下情况Last-Modified不能完成我们的要求。

  • Last-Modified最小单位是秒,如果所请求资源在一秒内更改,则Last-Modified校验失效。
  • 我们可能只更改了文件最后编辑时间,并未改变文件内容,即Last-Modified改变,但不希望重新获取资源。
  • 某些服务器不能精确的得到文件的最后修改时间。

此时我们在http头部补充E-tag字段,可以将某个能用来表明文件内容是否被更改的值(比如md5)来作为ETag,若服务器在响应一个资源时添加了ETag,当下一次浏览器再一次向服务器请求该资源时(前提是浏览器中上一次的资源被缓存过了),会在请求header中包含If-None-Match字段,值等于ETag

response.header:

可以看到请求中既有Etag也有Last-Modified

request.header:

此时状态码 304 Not Modified ,浏览器和服务器多确认了一次缓存有效性,再用的缓存。


缓存失败阶段

当服务器发现请求的资源已经修改过,服务器则返回请求数据,并且返回200状态码,如果服务器上没有相应数据,则返回404。


总结

为什么有时候明明命中了缓存,控制台中Status显示的不是 200 from cache ?是浏览器的原因:

  • 触发 200 from cache:

    • 直接点击链接访问

    • 输入网址按回车访问

    • 二维码扫描

  • 触发 304 Not Modified:

    • 刷新页面时触发

    • 设置了长缓存、但 Entity Tags 没有移除时触发

  • 适用火狐,Chrome亲测输入网址按回车或者刷新页面都触发200 from cache,不知道原因

一般会设置长时间的缓存,尽量命中缓存,然后靠更新静态文件的版本号来使缓存失效

流程图如下:简单讲就是,200from cache未发送请求,直接使用缓存,304 not modify为发送请求后确认缓存可用。 

首次请求:


再次载入某资源:

200from cache应该在为 缓存是否过期-否 分支

参考文章:

https://www.cnblogs.com/micro-chen/p/6547049.html

https://blog.csdn.net/huwei2003/article/details/70139062

https://blog.csdn.net/LeeSirbupt/article/details/54409931

https://blog.csdn.net/kikikind/article/details/6266101

猜你喜欢

转载自blog.csdn.net/m0_37205611/article/details/82751811