【问题标题】:If-None-Match headers ignore Content-Type and VaryIf-None-Match 标头忽略 Content-Type 和 Vary
【发布时间】:2020-07-03 01:31:39
【问题描述】:

我有一个同时提供 HTML 和多种 RDF 格式的 Web 应用程序(在下面的示例中,它是 RDF/XML)。 页面加载为 HTML(自然),然后请求其自己的 URL 作为 RDF/XML。

问题:看起来 Firefox 74.0(64 位)(在 Windows 上)混合了来自这两个请求的 ETag 值,忽略了不同的 Content-Types 以及存在的 Vary: Accept

当我重新加载页面时,我可以看到它使用 HTML 请求中第二个 (RDF/XML) 响应中的 ETag: "95e11fbc9e816b56",反之亦然:

Request URL: https://localhost:4443/6a6283d2-2a40-4882-b89d-8073a7c30e17/

Host: localhost:4443
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://localhost:4443/6a6283d2-2a40-4882-b89d-8073a7c30e17/
Connection: keep-alive
Cookie: _ga=GA1.1.828629977.1584086266; LinkedDataHub.first-time-message=true
Upgrade-Insecure-Requests: 1
If-None-Match: "95e11fbc9e816b56"
Cache-Control: max-age=0

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Strict-Transport-Security: max-age=31536000;includeSubDomains
ETag: "95e11fbc139f56de"
Cache-Control: max-age=3600, public
Last-Modified: Wed, 12 Feb 2020 23:05:15 GMT
Vary: Accept-Charset,Accept,Accept-Encoding
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Content-Encoding: gzip
Date: Sun, 22 Mar 2020 10:13:43 GMT
Request URL: https://localhost:4443/6a6283d2-2a40-4882-b89d-8073a7c30e17/

Host: localhost:4443
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: application/rdf+xml
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://localhost:4443/d376ee88-ff7d-48ee-81c4-1220c9f482f0/
Connection: keep-alive
Cookie: _ga=GA1.1.828629977.1584086266; LinkedDataHub.first-time-message=true
If-None-Match: "95e11fbc139f56de"
Cache-Control: max-age=0

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Strict-Transport-Security: max-age=31536000;includeSubDomains
ETag: "95e11fbc9e816b56"
Last-Modified: Wed, 12 Feb 2020 23:05:15 GMT
Vary: Accept-Charset,Accept
Content-Type: application/rdf+xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 22 Mar 2020 10:13:55 GMT

在 Chrome 上,我根本无法让它发送 If-None-Match 标头,但这可能是 due to the self-signed certificate

请注意,ETag 的值相似但不同:"95e11fbc139f56de""95e11fbc9e816b56"

这对我来说没有任何意义。有什么解释吗?谢谢。

相关规范为Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests

【问题讨论】:

  • 我建议为出现此错误的浏览器打开新的错误。

标签: http http-headers browser-cache etag http-caching


【解决方案1】:

问题本质上在于,您所依赖的行为不是 HTTP 标准强制要求的,而且浏览器也不会实现。

为了使您的方案正常工作,浏览器必须在其缓存中存储单个资源的多个表示形式。不幸的是,正如文章likethese 中所讨论的,他们没有这样做。

浏览器通常不会实现为每个 URL 存储多个变体的功能。这样做的理由是我们通常使用 Vary 的东西(主要是 Accept-Encoding 和 Accept-Language)在单个用户的上下文中不会经常更改。

所以问题不在于ETags,而是浏览器每次获得不同的表示时都会覆盖其缓存中的单个表示。

如果浏览器确实存储了多个表示,则该方案应该可以正常工作。在这种情况下,请注意在多个ETags 之间进行选择的是服务器,而不是客户端。客户端将发送一个带有它所知道的所有ETagsIf-None-Match 标头,并且由服务器决定哪个(如果有)与请求的表示匹配。

根据上面的文章,边缘服务器(相对于浏览器)确实在缓存中为每个资源保留了多个表示,因此您的方案仍有可能产生性能提升。

【讨论】:

  • 凯文,非常感谢您的回答。谷歌在这方面没有提供很多点击。我希望服务器能够以304 响应每种媒体类型的条件请求:HTML、RDF/XML 等等。它们是从相同的数据库结果(RDF 图)生成的,但显然不可互换。我认为为每种类型提供不同的标签(内容哈希+内容类型哈希)就足够了,因为浏览器会发送特定于内容类型的If-None-Match。但显然情况并非如此。我仍然很困惑 - 有没有办法实现我想要的?还是我的想法有问题。
  • 你这么说是有道理的 :) 但是我遇到的调试是浏览器在请求 HTML 时发送 RDF 表示的 ETtag,反之,在请求 RDF 时发送 HTML 表示的 ETag。所以他们永远不会在服务器上匹配,我总是得到200而不是304。这就是请求/响应示例应该显示的内容。看起来它只是使用最新的ETag,无论内容类型如何。我可能在这里遗漏了一些微不足道的东西。
  • 如果我编辑并重新发送请求并交换ETags,我会得到304...
  • “问题本质上是你依赖的行为不是 HTTP 标准所规定的”——事实上确实如此。
  • @KevinChristopherHenry - 他们不需要缓存,但如果他们需要,他们需要正确地缓存。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-10
  • 2012-11-27
  • 2018-06-24
  • 1970-01-01
  • 2016-06-07
  • 2019-08-26
  • 1970-01-01
相关资源
最近更新 更多