Cloudfront 对压缩文件和未压缩文件使用不同的 Content-Type

Cloudfront to use different Content-Type for compressed and uncompressed files

我正在为一个由静态站点生成器通过 S3 和 Cloudfront 生成的网站提供服务。文件正在以正确的 Content-Types 上传到 S3。 DNS 指向 Cloudfront,它使用 S3 存储桶作为其来源。 Cloudfront 负责加密和压缩。我告诉 Cloudfront 自动压缩 objects。在我决定将一些使用过的图像从 PNG 更改为 SVG 之前,它运行良好。

每当请求未压缩的文件时,它都会按 Content-Type (image/svg+xml) 集的原样交付,并且网站会正确呈现。但是,如果请求压缩文件,它会以默认 Content-Type (application/octet-stream) 交付,并且图像在渲染中丢失。如果我然后 right-click 在图像上并选择在新选项卡中打开图像,它将正确显示(没有页面的其余部分)。

无论使用何种浏览器,结果都是一样的。在 Firefox 中,我知道如何将其设置为强制请求压缩或未压缩的页面。我也试过 curl 来检查 headers。这些是结果:

λ curl --compressed -v -o /dev/null http://dev.example.com/img/logo-6998bdf68c.svg
* STATE: INIT => CONNECT handle 0x20049798; line 1090 (connection #-5000)
* Added connection 0. The cache now contains 1 members
*   Trying 52.222.157.200...
* STATE: CONNECT => WAITCONNECT handle 0x20049798; line 1143 (connection #0)
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to dev.example.com (52.222.157.200) port 80 (#0)
* STATE: WAITCONNECT => SENDPROTOCONNECT handle 0x20049798; line 1240 (connection #0)
* STATE: SENDPROTOCONNECT => DO handle 0x20049798; line 1258 (connection #0)
> GET /img/logo-6998bdf68c.svg HTTP/1.1
> Host: dev.example.com
> User-Agent: curl/7.44.0
> Accept: */*
> Accept-Encoding: deflate, gzip
>
* STATE: DO => DO_DONE handle 0x20049798; line 1337 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x20049798; line 1464 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x20049798; line 1474 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
< Content-Length: 7468
< Connection: keep-alive
< Date: Wed, 01 Mar 2017 13:31:33 GMT
< x-amz-meta-cb-modifiedtime: Wed, 01 Mar 2017 13:28:26 GMT
< Last-Modified: Wed, 01 Mar 2017 13:30:24 GMT
< ETag: "6998bdf68c8812d193dd799c644abfb6"
* Server AmazonS3 is not blacklisted
< Server: AmazonS3
< X-Cache: RefreshHit from cloudfront
< Via: 1.1 36c13eeffcddf77ad33d7874b28e6168.cloudfront.net (CloudFront)
< X-Amz-Cf-Id: jT86EeNn2vFYAU2Jagj_aDx6qQUBXFqiDhlcdfxLKrj5bCdAKBIbXQ==
<
{ [7468 bytes data]
* STATE: PERFORM => DONE handle 0x20049798; line 1632 (connection #0)
* Curl_done
100  7468  100  7468    0     0  44526      0 --:--:-- --:--:-- --:--:-- 48493
* Connection #0 to host dev.example.com left intact
* Expire cleared

未压缩的看起来更好:

λ curl -v -o /dev/null http://dev.example.com/img/logo-6998bdf68c.svg
* STATE: INIT => CONNECT handle 0x20049798; line 1090 (connection #-5000)
* Added connection 0. The cache now contains 1 members
*   Trying 52.222.157.203...
* STATE: CONNECT => WAITCONNECT handle 0x20049798; line 1143 (connection #0)
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to dev.example.com (52.222.157.203) port 80 (#0)
* STATE: WAITCONNECT => SENDPROTOCONNECT handle 0x20049798; line 1240 (connection #0)
* STATE: SENDPROTOCONNECT => DO handle 0x20049798; line 1258 (connection #0)
> GET /img/logo-6998bdf68c.svg HTTP/1.1
> Host: dev.example.com
> User-Agent: curl/7.44.0
> Accept: */*
>
* STATE: DO => DO_DONE handle 0x20049798; line 1337 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x20049798; line 1464 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x20049798; line 1474 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Content-Type: image/svg+xml
< Content-Length: 7468
< Connection: keep-alive
< Date: Wed, 01 Mar 2017 20:56:11 GMT
< x-amz-meta-cb-modifiedtime: Wed, 01 Mar 2017 20:39:17 GMT
< Last-Modified: Wed, 01 Mar 2017 20:41:13 GMT
< ETag: "6998bdf68c8812d193dd799c644abfb6"
* Server AmazonS3 is not blacklisted
< Server: AmazonS3
< Vary: Accept-Encoding
< X-Cache: RefreshHit from cloudfront
< Via: 1.1 ac27d939fa02703c4b28926f53f95083.cloudfront.net (CloudFront)
< X-Amz-Cf-Id: AlodMvGOKIoNb8zm5OuS7x_8TquQXzAAXg05efSMdIKgrPhwEPv4kA==
<
{ [2422 bytes data]
* STATE: PERFORM => DONE handle 0x20049798; line 1632 (connection #0)
* Curl_done
100  7468  100  7468    0     0  27667      0 --:--:-- --:--:-- --:--:-- 33639
* Connection #0 to host dev.example.com left intact

出于性能原因,我不想关闭压缩。看起来这只发生在 SVG 文件类型上。所有其他类型都有正确的,即。同样Content-Type。我已经尝试使缓存无效,甚至通过将缓存时间设置为 0 秒来完全关闭它。上传到 S3 时我无法上传压缩版本,因为上传过程是自动的,不能轻易更改单个文件。

我希望我做错了什么,因为那最容易修复。但我不知道设置可能有什么问题。我已经使用 Google 找到有类似问题的人,但看起来只有我一个人。谁有想法?

你误诊了问题。 CloudFront 不会更改 Content-Type.

但是,CloudFront 会根据请求的变化缓存同一对象的不同版本。

如果您注意到,您在这些对象上的 Last-Modified 时间是不同的。您最初在 S3 中设置了错误的内容类型。您随后修复了该问题,但 CloudFront 没有意识到元数据已更改,因为 ETag 没有更改,因此您得到了错误的 RefreshHit 响应。它根据宣传 gzip 编码支持的请求提供旧版本。如果对象的实际负载发生变化,CloudFront 可能已经更新了它的缓存。

执行 invalidation 清除缓存,几分钟后,这个问题就会消失。

我能够通过强制 MIME 类型为 "image/svg+xml" 而不是 "binary/octet-stream" 来解决它,后者是在与 python boto3 同步文件后选择的。

当您右键单击 S3 存储桶中的 svg 时,您可以通过查看元数据来检查 mimetype:

我不确定这是由 python 同步引起的,还是由 S3/Cloudfront 中的某些异常引起的。我必须补充一点,在那之后只是缓存失效不起作用。我必须使用正确的 mimetype 重新上传我的文件才能让云端访问 svg 正常工作。