浏览器从缓存

时间:2017-11-24 00:31:46

标签: caching browser http-headers browser-cache

我遇到一个无辜的请求后,我的客户端被注销了。我控制了两端,经过大量的调试后,我发现发生了以下情况:

  • 客户端使用正确的授权标头发送请求。
  • 服务器以304 Not Modified响应,没有任何授权标头。
  • 浏览器提供完整的响应,包括在其缓存中找到的过时的授权标头
  • 从现在开始,客户端使用过时的授权并被淘汰。

据我所知,the browser must not cache any request containing Authorization。尽管如此,

chrome://view-http-cache/http://localhost:10080/api/SearchHost

显示

HTTP/1.1 200 OK
Date: Thu, 23 Nov 2017 23:50:16 GMT
Vary: origin, accept-encoding, authorization, x-role
Cache-Control: must-revalidate
Server: 171123_073418-d8d7cb0 =
x-delay-seconds: 3
Authorization: Wl6pPirDLQqWqYv
Expires: Thu, 01 Jan 1970 00:00:00 GMT
ETag: "zUxy1pv3CQ3IYTFlBg3Z3vYovg3zSw2L"
Content-Encoding: gzip
Content-Type: application/json;charset=utf-8
Content-Length: 255

有趣的服务器标头通过一些内部信息替换Jetty服务器标头(出于安全原因不应该提供服务) - 忽略它。这就是curl所说的:

< HTTP/1.1 304 Not Modified
< Date: Thu, 23 Nov 2017 23:58:18 GMT
< Vary: origin, accept-encoding, authorization, x-role
< Cache-Control: must-revalidate
< Server: 171123_073418-d8d7cb0 =
< ETag: "zUxy1pv3CQ3IYTFlBg3Z3vYovg3zSw2L"
< x-delay-seconds: 3
< Content-Encoding: gzip

这也发生在Firefox中,虽然我目前无法重现它。  The RFC继续,看起来上面链接的答案并不确切:

  

除非在响应中存在允许存储此类响应的缓存指令

看起来响应是可缓存的。没关系,我确实想要缓存内容,但我不希望从缓存中提供Authorization标头。这可能吗?

我的问题的解释

我的服务器仅用于在响应登录请求时发送Authorization标头。这曾经很好地工作,问题来自新的要求。

我们的网站允许用户任意长时间登录(我们不做敏感业务)。我们正在更改授权令牌的格式,因此我们不希望强制所有用户再次登录。因此,我让服务器在看到过时但有效的授权令牌时发送更新的授权令牌。所以现在任何响应都可能包含授权令牌,但大部分都没有。

将仍然有效的响应与过时的授权令牌相结合的浏览器缓存会阻碍。

作为一种解决方法,当授权令牌存在时,我让服务器不发送etag。它有效,但我更喜欢一些更清洁的解决方案。

2 个答案:

答案 0 :(得分:5)

链接答案中的引用具有误导性,因为它省略了一个重要部分:&#34;如果缓存是共享的&#34;。 这是正确的引用(RFC7234 Section 3):

  

高速缓存绝不能存储对任何请求的响应,除非:...授权头字段(参见[RFC7235]的第4.2节)未出现在请求中, 如果共享高速缓存

RFC的那部分基本上是一个摘要。 这是完全相同的规则(RFC7234 Section 3.2):

  

共享缓存 绝不能使用带有Authorization标头字段的请求的缓存响应([RFC7235]的第4.2节)来满足任何后续请求,除非缓存允许存储此类响应的指令存在于响应中。

浏览器是否缓存共享缓存? 这在Introduction section of the RFC

中有解释
  相比之下,私有缓存专用于单个用户;通常,它们被部署为 用户代理的一个组件

这意味着浏览器缓存是私有缓存。 它不是共享缓存,因此上述规则不适用,这意味着Chrome和Firefox都可以正常工作。

现在的解决方案。

该规范建议在没有Authorization标头的情况下重用包含Authorization的缓存响应的可能性。 不幸的是,它还说该功能没有得到广泛实施。

因此,我能想到的最简单也是最具前瞻性的解决方案是确保包含授权令牌的任何响应都不会被缓存。 例如,只要服务器看到过时但有效的授权令牌,就发送一个新的有效签名和Cache-Control: no-store以禁止缓存。

此外,您必须永远不要向T <- 1:20 x <- 5 + 0.5 * T x.u <- 6 + 0.5 * T x.l <- 4 + 0.5 * T T2 <- 20:40 x2 <- 40 + 2 * T2 x.u2 <- 60 + 2 * T2 x.l2 <- 20 + 2 * T2 library(Cairo) CairoSVG('my.plot.svg', onefile = TRUE, pointsize = 12, width=6, height=9, bg="white") par(mfrow=c(2,1), xpd=NA) plot(T, x, xlab = 'x', ylab = 'y', type = 'l', col = 'green', lwd = 2, lty = 1, ylim = c(0, (max(x)+0.1)), cex.lab = 1.5) top.y <- grconvertY(1, from='npc') x.u = ifelse(x.u >= top.y, NA, x.u) lines(T, x.u, type = 'l', col = 'brown', lwd = 2, lty = 3) lines(T, x.l, type = 'l', col = 'brown', lwd = 2, lty = 3) plot(T2, x2, xlab = 'x2', ylab = 'y2', type = 'l', col = 'green', lwd = 2, lty = 1, ylim = c(0, (max(x2)+0.1)), cex.lab = 1.5) top.y <- grconvertY(1, from='npc') x.u2 = ifelse(x.u2 >= top.y, NA, x.u2) lines(T2, x.u2, type = 'l', col = 'brown', lwd = 2, lty = 3) lines(T2, x.l2, type = 'l', col = 'brown', lwd = 2, lty = 3) dev.off() 发送授权标头,因为Cache-Control: must-revalidate指令实际上允许缓存响应,包括共享缓存,这可能会在将来导致更多问题。

  

...除非在响应中存在允许存储此类响应的缓存指令。

     

在本规范中,以下Cache-Control响应指令(第5.2.2节)具有以下效果: 必须重新验证 ,public和s-maxage。

答案 1 :(得分:0)

我目前的解决方案是在每个响应中发送授权标头;在不需要授权时使用占位符值-

占位符值显然毫无意义,客户知道它并高兴地忽略它。

这个解决方案很丑陋,因为它为每个响应添加了大约20个字节,但这仍然比偶尔重新发送整个响应内容更好,就像我的问题中提到的方法一样。此外,使用HTTP / 2,它将是免费的。