网页请求在什么情况下会携带If-None-Match或If-Modified-Since头信息

我在django的设置启用了

'django.middleware.common.CommonMiddleware',
`django.middleware.http.ConditionalGetMiddleware`,

中间件,并且设置了USE_ETAGS = True
页面响应时有返回Etag数据,但请求时没有携带If-None-Match信息(图1,图2是静态文件的request和response信息),所以导致同一个页面每次刷新都是200状态码,而不是304。

图1:
clipboard.png

图2:
clipboard.png

问:我还需要做什么设置或操作才能让页面请求时携带If-None-Match或If-Modified-Since头信息。

阅读 14k
4 个回答

因为题主的两张图不是请求的同一个资源,没有办法很明确的得知上下文准确信息。下面我会用同一个资源的两次请求来解释下这个问题。

明确一个概念:

 浏览器使用缓存,不管使用的是强缓存还是协商缓存,都建立在该资源第一次请求之后的 **后续请求** 上,才会使用上缓存。

 也就是说假定该资源之前从未被加载过,那么第一次请求报文中,是不会有任何关于 cache 的头字段的(一般是:if-Modified-Since/ if-None-Match / cache-control )。

 只有在第一次的响应报文中,服务器返回了关于该资源的 cache-control、etag、last-modified 头字段,那么在第二次等的后续请求上才有可能重新带上这些字段发起条件请求。

 注意是可能会带上,下面会解释什么场景会带上。

第一次请求、应答报文如下:

图片描述

可以看到,响应报文返回了 cache-control: public, max-age=0 就是说,该资源可以被客户端或者代理缓存,也就是说谁都可以缓存,谁都可以取用。并且,该资源的缓存有效期是 0 (意思是缓存立马失效)。

刷新页面后,来看第二次的请求、应答报文:

图片描述

可以看到 请求报文中有条件请求头字段。if-Modified-Since 的值是第一次报文中 last-modified 的值; if-None-Match 的值是第一次报文中 etag 的值。

为什么会有条件请求字段呢。是因为缓存过期了(因为第一次响应报文中 max-age=0, 0就表示过期 ),所以浏览器会从缓存中查找是否有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% 【详细请看 http/1.1 rfc7234 解释】
  4. 如果连 last-modified 都没有返回,那你就老老实实发起 http 请求吧,不要再想缓存的事情了

总结: 浏览器发起http请求时,总是会先查看缓存,然后决定是否发起,以及发起什么类型的http请求。

=================
补充回答:

clipboard.png

图1比图2 response 响应头多了个 cache-control

新手上路,请多包涵
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏