关于asp.net:Amazon CloudFront是否未针对未更改的静态内容始终返回304(未修改)?

Amazon CloudFront not consistently returning 304 (Not Modified) for unchanged static content?

EC2 Web服务器网格在ELB负载均衡器后面运行。 ELB位于Amazon的CloudFront内容交付网络的背后。内容交付网络对我来说是非常新的。我的理解是,CloudFront应该通过在其"边缘"缓存静态内容来提高性能。但这不是正在发生的事情。

考虑一下我的EC2实例,其内容应始终具有5分钟的生命周期。对于静态内容,这通常意味着在我的web.config文件中声明以下内容:

1
2
3
<staticContent>
    <clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="00.00:05:00"/>
</staticContent>

...对于动态内容,通常意味着对HttpResponse对象执行以下命令:

1
2
resp.Cache.SetCacheability(HttpCacheability.Public);
resp.Cache.SetMaxAge(TimeSpan.FromMinutes(5));

以此为背景...

当我的浏览器直接点击ELB时,一切都会按预期进行。 Firebug始终显示,对于浏览器缓存中已存在,已经过五分钟过期但未在服务器上进行更改的内容,返回304(未修改)。以下是下载defs.js的响应标头,例如:

1
2
3
4
5
6
7
8
9
HTTP/1.1 304 Not Modified
Accept-Ranges: bytes
Cache-Control: public,max-age=300
Date: Tue, 22 Apr 2014 13:54:16 GMT
Etag:"0152435d158cf1:0"
Last-Modified: Tue, 15 Apr 2014 17:36:18 GMT
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Connection: keep-alive

IIS自4月15日以来正确地看到该文件没有更改,并返回304。

但是看起来当通过CloudFront抓取文件时会发生什么。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP/1.1 200 OK
Content-Type: application/x-javascript
Content-Length: 205
Connection: keep-alive
Accept-Ranges: bytes
Cache-Control: public,max-age=300
Date: Tue, 22 Apr 2014 14:07:33 GMT
Etag:"0152435d158cf1:0"
Last-Modified: Tue, 15 Apr 2014 17:36:18 GMT
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Age: 16
X-Cache: Hit from cloudfront
Via: 1.1 0f140ef1be762325ad24a7167aa57e65.cloudfront.net (CloudFront)
X-Amz-Cf-Id: Evfdhs-pxFojnzkQWuG-Ubp6B2TC5xbunhavG8ivXURdp2fw_noXjw==

在这种情况下,CloudFront会强制浏览器再次下载整个文件,尽管您可以看到:

(a)它知道自4月15日以来尚未对文件进行修改(请参阅Last-Modified标头),并且
(b)CloudFront确实有一个文件的缓存副本(请参阅X-Cache标头)

也许您想知道我的浏览器是否正在发送有效的If-Modified-Since标头。的确是。以下是请求标头:

1
2
3
4
5
6
7
8
9
10
11
12
GET /code/shared/defs.js HTTP/1.1
Host: d2fn6fv5a0cu3b.cloudfront.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:28.0) Gecko/20100101 Firefox/28.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://d2fn6fv5a0cu3b.cloudfront.net/
Connection: keep-alive
If-Modified-Since: Tue, 15 Apr 2014 17:36:18 GMT
If-None-Match:"0152435d158cf1:0"
Cache-Control: max-age=0

这是一个奇怪的情况。如果我只是坐在浏览器前面并继续执行页面重新加载(Cmd-R),则大约有一半的时间CloudFront会正确返回304,而另一半会错误地返回200和所有内容。等待五分钟到期,然后再与页面进行交互,主要产生200的结果,而仅产生304的结果。这种奇怪的行为适用于HTML页面上引用的所有文件(.css,.js,.png等)以及包含HTML页面本身。我知道我的应用程序编码正确,因为如上所述,直接击中ELB而不通过CloudFront结果会达到预期的304结果。有什么想法吗?


答案是在一个看似无关的亚马逊文档中写的一个晦涩的句子中找到的:

When you configure CloudFront to forward cookies to your origin [...] If-Modified-Since and If-None-Match conditional requests are not supported.

很奇怪,但实际上现实情况要差得多;不是将cookie转发到您的原始服务器会禁用条件请求,而是有时会禁用它们-直到HTTP结果代码(304与200)几乎是随机的。

请务必注意,即使您根本不使用Cookie,也会被这种奇怪的行为所困扰。如下图所示,将"转发Cookie"下拉列表设置为"无"仍然是绝对必要的:

enter

该解决方案虽然给您带来了另一个问题。您要告诉CloudFront在将请求转发到您的来源之前完全剥离所有cookie。但是您的原始服务器可能需要这些cookie。此外,如果您使用ELB(负载平衡器)作为来源,则ELB用来维持粘性会话所依赖的关键cookie将被完全删除。不好。

解决Cookie剥离问题的方法将取决于您网站的组织方式。就我而言,仅在将AJAX数据发布到myDomain.com/ajax/时才需要传输cookie(与会话有关或与会话有关)。因为所有与Cookie相关的URL都属于ajax/*类别,所以必须为该路径创建一个新的行为规则,并且在该规则(仅该规则)中,将"转发Cookie"下拉列表设置为"全部",而不是"没有。"

就这样。希望这对某人有帮助。