首页 > 解决方案 > If-None-Match 标头忽略 Content-Type 和 Vary

问题描述

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

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

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

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标头,但这可能是由于 self-signed certificate

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

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

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

标签: httphttp-headersbrowser-cacheetaghttp-caching

解决方案


本质上,问题在于您所依赖的行为不是 HTTP 标准规定的,也不是浏览器实现的。

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

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

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

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

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


推荐阅读