Search code examples
javascriptruby-on-railscdnamazon-cloudfront

Serving HTML and assets from Cloudfront among dynamic content


I have a basic app where users can upload a bunch of HTML files (index.html, mypage.html) and a bunch of assets (myimage.jpg, myscript.js), and access these on their own url like www.mysite.com/username/index.html.

However, my site adds a bunch of things to the uploaded HTML: The ability to add comments, bookmarks, etc. All this is injected via JS.

In my Rails app, right now I'm loading the user uploaded content from S3 in the controller, and outputting it in my view along with a bunch of JS:

def show
   # load HTML from S3
   # strip out everything between body tags and put in @body var
   # render view that outputs @body on a page with a bunch of JS
end

However, this is super slow because:

  1. I'm not taking advantage of CDN caching for the user uploaded files
  2. I'm not putting any of the HTTP calls on the client. The client is waiting for the server to load the content from S3 before seeing any content.

What I would like to on a request is the following

  1. The Rails app returns a bare HTMl page with JS
  2. The JS loads the HTML file from Cloudfront (taking advantage of caching)
  3. JS injects the HTML on the page, along with the comments, bookmarking, etc

I think this would be great, but I'm stuck on file versioning. In order to take advantage of caching, I want to set long TTLs and utilize file verisoning. However, I don't want to run through all the user-uploaded HTML and replace all assets tags from /myimage.jpg to /myimage-VERSION.jpg, and I don't want long crazy URLs like www.mysite.com/username/index-VERSION.html

I'm wondering if there's smart way to do this? Basically fetching HTML from Cloudfront, injecting with HTML from my Rails app, and taking advantage of versioned files while keeping nice URL's and the original HTML files untouched.

Or should I rather go with using memcached on the controller side?

Any ideas?


Solution

  • You can setup CloudFront to use your Rails app as a custom origin. Send requests to CloudFront first. When a new, uncached request comes into CloudFront, your app will be hit first to prime CloudFront's cache. This is when you would do all of your custom processing before delivering the finished page to CloudFront for caching. Set appropriate caching ETag or similar and CloudFront will request updates from you for which you can supply 304 or new content.