How do I use SSL only for actions, not stylesheets, javascript, and images...

I've added SSL to my backend, and the performance quickly went to hell. I finally figured out that files served via SSL, particularly the big files such as prototype.js, don't get cached (in the browser, I guess [Safari]) when served via SSL. They get downloaded for each page. Turn off SSL, and they are cached.

Problem is the stylesheet_link_tag and javascript_include_tag create relative links, which means if the main url is https, it will server those files with https.

Has anyone figured out a way around this, to only serve the action with SSL, not the support files? This seems like a common problem that at least BaseCamp would have run into.

Thanks, Brett

Kinda doubt you wanna do that my friend. Worse than not caching some of your files will be the annoying "this page is attempting to access insecure files do you want to continue" (something like that) messages that most of your users will receive if you do that.

Good Luck, Tim

Hi Brett,

I've added SSL to my backend, and the performance quickly went to hell. I finally figured out that files served via SSL, particularly the big files such as prototype.js, don't get cached (in the browser, I guess [Safari]) when served via SSL. They get downloaded for each page. Turn off SSL, and they are cached.

Problem is the stylesheet_link_tag and javascript_include_tag create relative links, which means if the main url is https, it will server those files with https.

Has anyone figured out a way around this, to only serve the action with SSL, not the support files? This seems like a common problem that at least BaseCamp would have run into.

If you try to serve the support files using anything other than SSL most browsers will display nasty error messages to the users.

It is possible to cache images, javascript and stylesheets using SSL though, just make sure the Cache-Control and Expires HTTP headers are sent in each response.

- --

Thanks,

Dan

Tim: Really, even with an official SSL certificate (from RapidSSL)? I had done a quick test with mixed SSL/non-SSL content and didn't see the warning, but maybe my browser was already set to ignore that.

Dan: How do I set the Cache-Control and Expires headers just for images and stylesheets/javascript? I don't want the main content cached - it needs to be regenerated each time. It looks like if I set it in the controller it will be used for the action as well.

Cheers, Brett

Brett Walker wrote:

Tim: Really, even with an official SSL certificate (from RapidSSL)? I had done a quick test with mixed SSL/non-SSL content and didn't see the warning, but maybe my browser was already set to ignore that.

Yeah there's no doubt, most if not all of your users will get a warning message if anything on your page is drawn from an insecure area. It has nothing to do with who issued the certificate.

chau! Tim

Hi Brett,

Dan: How do I set the Cache-Control and Expires headers just for images and stylesheets/javascript? I don't want the main content cached - it needs to be regenerated each time. It looks like if I set it in the controller it will be used for the action as well.

What server are you using in front of your rails app? Apache, Nginx, LightTPD or something else? Most server software has a way of setting the Cache-Control and Expires header for a matching URL.

For example I use the following in my Nginx configuration:

   location ~ ^/(images|javascripts|stylesheets)/ {      expires 10y;    }

Apache and lighttpd have their mod_expires modules which can do basically the same thing.

Dan, I'm using Apache 2.2.3 for the static stuff and Mongrel. I have found where you can cause caching at the Apache level, using ExpiresByType. But doesn't it mess up your deploy? I mean, if you change your stylesheet, users won't see it for 10 years (expires 10y;), because of the caching statement. How are you dealing with that?

Cheers, Brett

Append a version number to your CSS and javascript files maybe works? Or don't cache it for ten years, only one day. But it doesn't sound like a real solution.

Dan, I'm using Apache 2.2.3 for the static stuff and Mongrel. I have found where you can cause caching at the Apache level, using ExpiresByType. But doesn't it mess up your deploy? I mean, if you change your stylesheet, users won't see it for 10 years (expires 10y;), because of the caching statement. How are you dealing with that?

http://www.agilewebdevelopment.com/plugins/assetpackager

works for us (no ssl, but the caching side of things anyway).

Ther's another one out there that I can't remember the name of that instead of doing /path/to/style.css?12345 does /path/to/style_12345.css

-philip

Hi Brett,

Dan, I'm using Apache 2.2.3 for the static stuff and Mongrel. I have found where you can cause caching at the Apache level, using ExpiresByType. But doesn't it mess up your deploy? I mean, if you change your stylesheet, users won't see it for 10 years (expires 10y;), because of the caching statement. How are you dealing with that?

If you're using the stylesheet_link_tag, javascript_include_tag, or the image_tag methods from ActionView::Helpers::AssetTagHelper the timestamp of the file will be appended onto the query string. (the part after the ? in the URL) So you'll get URLs like this:

   http://www.example.com/stylesheets/application.css?1168541088

That means whenever you change the actual file, the query string will change and "bust" the cache, causing the browser to download what it thinks is a new file. Once downloaded the file should be cached for a long period of time assuming the front-end server is sending the correct caching headers.

- --

Thanks,

Dan

Philip: I've used the assetpackager plugin before, but not on this site. I will look at that and see if it helps.

Dan: I'm currently using the stylesheet_link_tag. Honestly, it seems like in my testing if I use the ExpiresByType caching mechanism, the caching *doesn't* break when the query string changes. When there is no ExpiresByType, it seems to work correctly (in the http case).

Now you have me doubting myself. I need to do some more indepth testing on this.

Question: I've been using Safari for testing, because I can easily see what files are being downloaded for a page, the size of each one, and their progress in downloading (Window -> Activity). So I can actually see the progress as it downloads the 60K prototype.js file, and therefore know that it's not coming from the cache.

Is there an extension in Firefox that will give the same information? I would like to be testing with that as well.

Thanks, Brett

Hi Brett,

Philip: I've used the assetpackager plugin before, but not on this site. I will look at that and see if it helps.

I highly recommend this too if you have more than one stylesheet and/or JavaScript file. Not only will it concatenate all the stylesheets into one main stylesheet, and all the JavaScript files into one Javascript file, it will compress them down so they are transfered more quickly to the end user. Combine that with gzip compression for the smallest transfer size possible.

Dan: I'm currently using the stylesheet_link_tag. Honestly, it seems like in my testing if I use the ExpiresByType caching mechanism, the caching *doesn't* break when the query string changes. When there is no ExpiresByType, it seems to work correctly (in the http case).

Now you have me doubting myself. I need to do some more indepth testing on this.

Here's an article that goes more in-depth into how the top four browsers handle caching:

   The State of Browser Caching

Question: I've been using Safari for testing, because I can easily see what files are being downloaded for a page, the size of each one, and their progress in downloading (Window -> Activity). So I can actually see the progress as it downloads the 60K prototype.js file, and therefore know that it's not coming from the cache.

I wouldn't believe everything you see in Safari's Activity menu. If you "tail -f" your web server logs while accessing a page that links to (properly configured) cached files, your web server should only show the initial request and nothing for the cached files. Safari's Activity menu will display all the requests identically regardless of whether the content was retrieved from the browser cache or the server.

Is there an extension in Firefox that will give the same information? I would like to be testing with that as well.

I'm not sure about a Firefox plugin. I use the server logs, since they don't lie, and they work for every browser.