通过S3在Amazon CloudFront提供经过gzip压缩的CSS和JavaScript文件

197

我一直在寻找使我的网站加载更快的方法,其中一种我想要探索的方式是更多地使用Cloudfront。

由于Cloudfront最初并不是作为自定义源CDN设计的,也不支持gzip压缩,因此迄今为止,我一直在使用它来托管所有的图片,这些图片通过其Cloudfront cname在我的网站代码中引用,并且使用far-futures头进行优化。

另一方面,CSS和JavaScript文件则托管在我的自己的服务器上,因为直到现在我一直认为它们不能从Cloudfront服务中以gzip格式提供,并且gzip压缩(约75%)带来的性能提升比使用CDN(约50%)要大:Amazon S3(因此也包括Cloudfront)无法通过使用浏览器发送的HTTP Accept-Encoding头来标准地提供gzip压缩内容,则无法动态压缩和服务组件。

因此,直到现在我一直认为必须在两个选择之间做出选择:

  1. 将所有资产移动到Amazon CloudFront并放弃GZipping;

  2. 保留组件自托管,并配置我们的服务器以检测输入请求并根据需要执行即时GZip压缩,这是我迄今为止选择的做法。

虽然曾经有解决此问题的方法,但实际上基本上这些方法都无法解决。 [链接]。

现在,似乎Amazon Cloudfront支持自定义源,并且如果您使用自定义源,则现在可以使用标准的HTTP Accept-Encoding方法提供gzip压缩内容。 [链接]。

到目前为止,我还没有能够在我的服务器上实现这个新功能。我找到的唯一详细说明这个更改的博客文章似乎暗示只有选择自定义源(工作区变通方法除外,我不想使用)才能启用gzip压缩,而我宁愿不这样做:我觉得从我的Cloudfront服务器托管相应的文件并从那里链接更简单。尽管我仔细阅读了文档,但我不知道:

  • 新功能是否意味着文件必须通过自定义源托管在我的域服务器上,并且如果是这样,哪些代码设置会实现这一点;

  • 如何配置CSS和JavaScript头文件以确保它们从Cloudfront提供Gzip压缩。

6个回答

205

更新:Amazon现在支持gzip压缩,因此不再需要执行以下操作。Amazon公告

原始回答:

答案是对CSS和JavaScript文件进行gzip压缩。是的,你没看错。

gzip -9 production.min.css

这将生成production.min.css.gz。删除.gz,将其上传到S3(或任何您正在使用的源服务器),并明确设置文件的Content-Encoding头为gzip

虽然这不是即时压缩,但您可以很容易地将其包装进您的构建/部署脚本中。它的优点是:

  1. 请求文件时,Apache不需要对内容进行压缩,因此不需要CPU。
  2. 文件以最高压缩级别进行压缩(假设使用命令)。
  3. 您正在从CDN上提供文件。

假设您的CSS/JavaScript文件已经被(a)缩小,并且(b)足够大,以证明需要在用户计算机上解压缩所耗费的CPU时间有显着性能提升。

只需记住:如果您更改了一个在CloudFront中缓存的文件,则在进行此类更改后,请务必使缓存失效。


37
阅读了您提供的链接后,我必须说博客作者并不了解情况。他说:“但是,如果用户的浏览器不支持gzip编码,则你网站上压缩的样式表和JavaScript文件将无法为该用户正常工作。”然而,这种浏览器可能太旧以至于无法运行你的样式表和脚本文件。这些用户只占总用户数的一小部分。 - Skyler Johnson
3
更新:我解决了。它没有显示的原因是我忘记将 Content-Type 设置为 text/css。如果你这样做,就没问题了,尽管由于以下原因,在 S3 中似乎无法添加“Accept-Encoding: Vary”头部(这有助于 Google 速度评分):[链接]。另外,我将 Cache-control 设置为缓存资源,但它似乎并没有缓存它... - Donald Jenkins
32
通过谷歌找到这篇文章,很抱歉必须说这不是一个好的建议。尽管 <1% 的 桌面 浏览器无法处理压缩内容,但是许多 移动浏览器 不能。它们能否处理取决于您要针对哪个受众群体;但是大多数旧款 Nokia S40 手机例如支持 gzip 压缩的存在问题。正确的方法是使用“自定义源”,指向Apache/IIS Web 服务器,该服务器可以进行内容压缩并提供适当的 HTTP 标头。以下是一篇描述其要点的博客文章:http://www.nomitor.com/blog/2010/11/10/gzip-support-for-amazon-web-services-cloudfront/ - user84609
14
现在的情况如何,是指2015年初的情况吗?@JesperMortensen和Simon Peck发的链接仍然相关吗? - ItalyPaleAle
5
2015年12月,亚马逊宣布支持gzip压缩,因此现在这个不再相关,只需上传基本文件即可正常运行。https://aws.amazon.com/blogs/aws/new-gzip-compression-support-for-amazon-cloudfront/ - Sean
显示剩余7条评论

15

我的回答是对这篇文章的进一步发挥:http://blog.kenweiner.com/2009/08/serving-gzipped-javascript-files-from.html

在skyler的回答的基础上,你可以上传一个经过gzip压缩和一个未经gzip压缩的css和js版本。但要注意文件命名并在Safari中进行测试,因为Safari不能处理 .css.gz.js.gz 文件。

site.jssite.js.jgz,以及 site.csssite.gz.css(您需要将 content-encoding 标头设置为正确的MIME类型才能正确提供服务)

然后在页面中添加如下内容:

<script type="text/javascript">var sr_gzipEnabled = false;</script> 
<script type="text/javascript" src="http://d2ft4b0ve1aur1.cloudfront.net/js-050/sr.gzipcheck.js.jgz"></script> 

<noscript> 
  <link type="text/css" rel="stylesheet" href="http://d2ft4b0ve1aur1.cloudfront.net/css-050/sr-br-min.css">
</noscript> 
<script type="text/javascript"> 
(function () {
    var sr_css_file = 'http://d2ft4b0ve1aur1.cloudfront.net/css-050/sr-br-min.css';
    if (sr_gzipEnabled) {
      sr_css_file = 'http://d2ft4b0ve1aur1.cloudfront.net/css-050/sr-br-min.css.gz';
    }

    var head = document.getElementsByTagName("head")[0];
    if (head) {
        var scriptStyles = document.createElement("link");
        scriptStyles.rel = "stylesheet";
        scriptStyles.type = "text/css";
        scriptStyles.href = sr_css_file;
        head.appendChild(scriptStyles);
        //alert('adding css to header:'+sr_css_file);
     }
}());
</script> 

gzipcheck.js.jgz只是sr_gzipEnabled=true;,这个代码可以检测浏览器是否能够处理压缩的代码并提供备用方案。

接下来在页脚做类似的事情,假设所有的js都在一个文件中,并且可以放在页脚中。

<div id="sr_js"></div> 
<script type="text/javascript"> 
(function () {
    var sr_js_file = 'http://d2ft4b0ve1aur1.cloudfront.net/js-050/sr-br-min.js';
    if (sr_gzipEnabled) {
       sr_js_file = 'http://d2ft4b0ve1aur1.cloudfront.net/js-050/sr-br-min.js.jgz';
    }
    var sr_script_tag = document.getElementById("sr_js");         
    if (sr_script_tag) {
    var scriptStyles = document.createElement("script");
    scriptStyles.type = "text/javascript";
    scriptStyles.src = sr_js_file;
    sr_script_tag.appendChild(scriptStyles);
    //alert('adding js to footer:'+sr_js_file);
    }
}());
</script> 

更新:亚马逊现在支持gzip压缩。官方已经发布了通知,因此不再需要这个方法。 亚马逊官方通知


非常感谢您的建议。如果我理解正确,您正在处理用户的浏览器无法读取gzipped文件的情况,尽管这种情况在现今的浏览器中只占相当小的比例。如果您参考我在问题中发布的链接[link],那么这种解决方案可能存在一个缺点,即您无法缓存页面,因为它只能在每次用户加载页面时动态运行您的代码才能起作用(当然我的代码是这样的)。 - Donald Jenkins
@DonaldJenkins 我认为js文件仍将被缓存。当您在js代码片段中构建脚本标签时,浏览器仍需调用js文件。我相信,如果js文件已经存在于缓存中,则浏览器会直接从缓存中使用该文件。 - Sean
2
测试页面http://blog.kosny.com/testpages/safari-gz/表明警告“小心在Safari中命名和测试。因为Safari无法处理css.gz或js.gz”已经过时。在Mavericks上的Safari 7和iOS 7上的Safari中,css.gz和js.gz都可以使用。我不知道这个变化是什么时候发生的,我只是用我有的设备进行测试。 - garyrob

14

Cloudfront支持gzip压缩。

Cloudfront通过HTTP 1.0连接到您的服务器。默认情况下,包括nginx在内的一些Web服务器不会向HTTP 1.0连接提供gzip压缩内容,但是您可以通过添加以下内容来启用:

gzip_http_version 1.0

在您的nginx配置中加入以下内容。无论使用哪个web服务器,都可以设置等效的配置。

这样做的副作用是使HTTP 1.0连接的长连接不起作用,但由于压缩的好处巨大,这绝对是值得权衡的。

摘自http://www.cdnplanet.com/blog/gzip-nginx-cloudfront/

编辑

通过Amazon CloudFront即时压缩内容存在风险,可能不应该这样做。基本上,如果您的Web服务器正在压缩内容,则不会设置Content-Length,而是将数据作为分块发送。

如果Cloudfront与您的服务器之间的连接被中断并过早地断开,则Cloudfront仍会缓存部分结果,并将其作为缓存版本提供,直至到期。

首选的答案是先将其压缩到磁盘上,然后再提供gzipped版本,因为Nginx将能够设置Content-Length标题,因此Cloudfront将丢弃截断的版本。


5
这个答案与问题无关。Nginx不等同于S3和Cloudfront。 - Jonathan
@Danack,你是否遇到了许多Cloudfront缓存半获取文件的问题,因为这个问题?我试图了解在实践中这对你来说有多大的问题。 - poshest
1
@poshest 发生了。在服务器上实时压缩文件几乎没有什么好处(因为gzip在服务器上非常快),所以我一看到它发生就立刻关闭了。数据损坏比“第一个字节的时间”在极少数情况下慢200毫秒更严重,这种情况只会出现在内容尚未以gzip格式存在的情况下。 - Danack
如果一个资源在头部中缺少 Content-Length 属性但包括 Transfer-Encoding: chunked(如常见的 gzip 资源),CloudFront 将不会缓存未收到终止块的部分资源。如果这两个属性都缺失,则可能会缓存不完整的资源。详情请参阅:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorCustomOrigin.html#ResponseCustomDroppedTCPConnections - Cody Duval

5

昨天,亚马逊宣布了一个新功能,您现在可以在您的分发上启用gzip。

这个功能与S3一起使用,无需自己添加.gz文件。我今天尝试了这个新功能,效果非常好。(需要使您当前的对象失效)

更多信息


5
我们最近为uSwitch.com进行了一些优化,以压缩我们网站上的某些静态资源。虽然我们设置了一个完整的nginx代理来完成这个任务,但我还是编写了一个小型的Heroku应用程序,用于在CloudFront和S3之间进行代理以压缩内容:http://dfl8.co 由于公开访问的S3对象可以使用简单的URL结构进行访问,http://dfl8.co就使用了相同的结构。也就是说,以下URL是等效的:
http://pingles-example.s3.amazonaws.com/sample.css
http://pingles-example.dfl8.co/sample.css
http://d1a4f3qx63eykc.cloudfront.net/sample.css

0

您可以配置CloudFront自动压缩某些类型的文件并提供压缩文件。

请参阅AWS 开发人员指南


你能否添加更多关于你的解决方案的信息(比如一个例子),以使它成为更好的答案。 - Yagami Light

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接