Monday, August 31, 2009

Serving Gzipped Javascript Files from Amazon CloudFront

It is well-known that using a content delivery network (CDN) and compressing an HTTP response with gzip can significantly improve the performance and reduce the cost of a web site. If your CDN is Amazon's CloudFront, you'll face difficulties serving gzipped content to browsers that support it. Most web servers are able to examine the HTTP request headers sent by the browser and dynamically choose whether to deliver compressed or uncompressed content. CloudFront, however, does not yet offer this feature.

People have overcome this problem by manually inspecting the Accept-Encoding request header for a dynamically served page and writing references to either original or compressed files accordingly using a naming convention like myscript.js and myscript.js.gz for regular and compressed files respectively.

If all your pages are statically served from CloudFront, however, there is no opportunity to inspect the request headers. Javascript running on a statically served page has no ability to ask the browser if it supports gzipped content. We found ourselves in this situation and resorted to the following solution to determine if the browser supports gzip:

1) Create a small gzipped file, gzipcheck.js.jgz, and make it available in CloudFront. This file should contain one line of code:
gzipEnabled = true;

2) Use the following code to attempt to load and run this file. You'll probably want to put it in the HTML HEAD section before any other Javascript code.
<script type="text/javascript" src="gzipcheck.js.jgz">
</script>

If the file loads, it sets a flag, gzipEnabled, that indicates whether or not the browser supports gzip.

Use the result to drive a file naming convention for references to other static files. For example, you can upload and reference each compressed Javascript file with an additional .jgz extension. Why .jgz instead of .gz? Because of an annoying limitation of Safari.

When you upload your files to S3/CloudFront, make sure to set the proper HTTP response headers on your files that end in .jgz:
Content-Encoding = gzip
Content-Type = application/x-javascript

And if you want browsers to cache your files forever (almost):
Cache-Control = max-age=315360000
Expires = Tue, 31 Dec 2019 20:00:00 GMT

Thanks to Ricardo Rangel who helped design and code this solution.

10 comments:

andy said...

Hi Ken,

thank you for bringing up the topic. check out how CloudBerry Explorer can automate serving GZip contents from Amazon S3.

Thanks
Andy

Jules said...

No matter what I do, I cannot get these to cache in the browser. It's very frustrating!

Anonymous said...

Dear Author blog.kenweiner.com !
It is remarkable, this valuable opinion

Anonymous said...

I want to quote your post in my blog. It can?
And you et an account on Twitter?

Ken said...

Of course you can quote this post in another blog. And my Twitter account is http://twitter.com/kweiner

pauldwaite said...

Out of interest, do you get a non-trivial number of requests from browsers that don’t support gzip? I assumed everything non-obscure did nowadays.

Anonymous said...

While following your steps, I found that instead of having “me” as a group it had the following: 166839 166839

Anonymous said...

Thank you for taking the time to make that clearer.

Al Serize said...

This is a great alternative, however, after just about 2 days worth of research, I was able to get my EC2 Instance working with CloudFront serving gzip files.

The issue with CloudFront is that although it supports gzip, the request from CloudFront to the origin server is done by HTTP/1.0 and IIS 7.x UI only configures HTTP/1.1 gzip requests. In other words, you must go down to the XML files and edit them.


I found this blog that pretty much gave me the code I needed to get the applicationHost.config XML and web.config files working: http://world.episerver.com/Blogs/Marco-ter-Horst--Mirabeau/Dates/2012/2/Configuring-GZip-with-IIS-75/

the only thing to add to the applicationHost.config file is the following tag within the httpCompression noCompressionForHttp10="false" and BINGO you got yourself a working gzip Frontcloud.

Enjoy!

Al Serize said...

This is a great alternative, however, after a few hours worth of research and playing with my EC2 instance to get this to work serverside I was able to get it working. I now have my EC2 instance serving gzip files thru FrontCloud. Here is what you need to do:

Go to this website: http://world.episerver.com/Blogs/Marco-ter-Horst--Mirabeau/Dates/2012/2/Configuring-GZip-with-IIS-75/

Follow the instructions and copy the code to the appropriate files. Also add the following attribute to the httpCompression tag on the applicationHost.config file: noCompressionForHttp10="false"

Since CF only supports HTTP/1.0 requests and the new versions of IIS UI are set to only configure gzip on HTTP/1.1, editing the code would allow you to force IIS to serve Gzip compress files to HTTP/1.0 requests.

I hope this can help and you don't have to spend as much time as I did on this....

Regards,
Al