HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

It's a good practice to use many small Javascript and CSS files instead of one large Javascript/CSS file for better code maintainability, but bad in terms of website performance. Although you should write your Javascript code in small files and break large CSS files into small chunks but when browser requests those javascript and css files, it makes one Http request per file. Every Http Request results in a network roundtrip form your browser to the server and the delay in reaching the server and coming back to the browser is called latency. So, if you have four javascripts and three css files loaded by a page, you are wasting time in seven network roundtrips. Within USA, latency is average 70ms. So, you waste 7x70 = 490ms, about half a second of delay. Outside USA, average latency is around 200ms. So, that means 1400ms of waiting. Browser cannot show the page properly until Css and Javascripts are fully loaded. So, the more latency you have, the slower page loads.

Here's a graph that shows how each request latency adds up and introduces significant delay in page loading:

image

You can reduce the wait time by using a CDN. Read my previous blog post about using CDN. However, a better solution is to deliver multiple files over one request using an HttpHandler that combines several files and delivers as one output. So, instead of putting many <script> or <link> tag, you just put one <script> and one <link> tag, and point them to the HttpHandler. You tell the handler which files to combine and it delivers those files in one response. This saves browser from making many requests and eliminates the latency.

image

Here you can see how much improvement you get if you can combine multiple javascripts and css into one.

In a typical web page, you will see many javascripts referenced:

<script type="text/javascript" src="/Content/JScript/jquery.js">
</script>
<script type="text/javascript" src="/Content/JScript/jDate.js">
</script>
<script type="text/javascript" src="/Content/JScript/jQuery.Core.js">
</script>
<script type="text/javascript" src="/Content/JScript/jQuery.Delegate.js">
</script>
<script type="text/javascript" src="/Content/JScript/jQuery.Validation.js">
</script>

Instead of these individual <script> tags, you can use only one <script> tag to serve the whole set of scripts using an Http Handler:

<script type="text/javascript" 
src="HttpCombiner.ashx?s=jQueryScripts&t=text/javascript&v=1" >
</script>

The Http Handler reads the file names defined in a configuration and combines all those files and delivers as one response. It delivers the response as gzip compressed to save bandwidth. Moreover, it generates proper cache header to cache the response in browser cache, so that, browser does not request it again on future visits.

You can find details about the HttpHandler from this CodeProject article:

http://www.codeproject.com/KB/aspnet/HttpCombine.aspx

You can also get the latest code from this code site:

http://code.msdn.microsoft.com/HttpCombiner

That's it! Make your website faster to load, get more users and earn more revenue.

Share this post :
kick it on DotNetKicks.com
Published Thu, Aug 28 2008 19:43 by omar
Filed under: ,

Comments

# alternative for loading ajax / javascript framework

Friday, August 29, 2008 5:44 AM by Teun Roodvoets

An alternative way to load the jQuery files could be: Google API's

code.google.com/.../ajaxlibs

Advantages:

- Multiple sites will use the same Uri to load the .js files hosted by Google, so the files will be loaded from your browsercache, minimizing the load in a first visit scenario.

- Google uses a CDN to distribute these files

- The browser connects to a different domain and therefore doesn't consume of the 4 concurrent connections a browser makes to the same domain

- It's free (so your consuming a bit less traffic from your ISP)

Disadvantages:

- Google can track to which pages and sites your visitors are going and create profiles of interest, but they already can on sites that use AdSense, Maps, Analytics, Picasa and Google Gadgets

- Some browsers block external links depending on it's security settings (f.i. IE8 InPrivate Blocking)

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Tuesday, September 02, 2008 3:58 AM by Giles

Why not use the AJAXControlToolkit to combine the script files and embed them in the assembly? That way you get GZIP'd and concatenated files in one hit for free.

The only downside is that the .Net 2.0 version doesn't allow you to disable compression, which means that if HTTP compression is enabled on your IIS server you'll need to edit the ScriptManager class to add a property to allow compression to be turned off!

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Tuesday, September 02, 2008 4:22 AM by omar

Hi Teun,

I have used Google's API as well. Please check out the jquery path in web.config. It's coming from Google's server. You are right about the pros and cons of using this. Thanks for listing this down.

Hi Giles,

AJAXControlToolkit cannot combine CSS and your own Javascripts which are not part of Extenders.

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Thursday, September 11, 2008 3:44 AM by Dan

Great article. I have tried your solution and it works fine for CSS files but does not seem to process images correctly. I have a master page with the css file link in the header. All the text formating and layouts are correct however none of the images are being downloaded.

Thanks

Dan

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Thursday, September 11, 2008 4:11 AM by omar

Say you have CSS file in /css/css.css and you have used relative image paths file test.gif which is expected to be in /css/test.gif.

When you combine the CSS and deliver using the handler, the handler is hit on the root URL e.g. /HttpCombiner. So, it it delivers CSS that refers image in the current folder, it does not get the /css/test.gif file.

To solve this problem, you have to use root path in all images inside CSS. For ex, use /css/test.gif everywhere. Or you can put the CSS files in the root of the website and use paths accordingly.

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Thursday, September 11, 2008 4:12 AM by fabrice

Hi Omar,

I did a test website to try your httpmodule.

It's amazing, thank very much

However, when i change a value in a css file and then the version in the link to update the cache)(<link type="text/css" rel="Stylesheet" href="HttpCombiner.ashx?s=Set_Css&t=text/css&v=1.2" />) :

firefox 3 doesn't refresh it but it does on IE7.

There is no prob with the javascript on firefox 3 and IE7

Do you have that problem as well ?

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Thursday, September 11, 2008 4:22 AM by omar

I believe Firefox is caching the main page and not seeing the new <link> tag being generated. Try putting <%@ OutputCache NoStore="true" Location="None" %> on the .aspx page.

Browsers cache using URL. If URL changes, it gets a new copy.

# Problems in FireFox 3

Friday, September 12, 2008 9:08 AM by Nikolay Raychev

Hi Omar,

Your tool is really great. We will be using it to combine some CSS files in the next release of SilverlightShow. It works fine under most browsers but I'm having problems in FF3. For some reason FF does not recognize the content of some of the combined files.

I have disabled caching on all my browsers. When I move the desired styles in another file FF recognizes them. It happens exactly for the last appended file. I'm sure that caching is not the problem because when I open the combined css file in another tab the styles do exist. May be there is somthing with encoding. I'll make some more research and let you know what happens.

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Friday, September 12, 2008 12:45 PM by nhm tanveer hossain khan (hasan)

hi mishu bhai,

this is very nice topic. we have been using the same technique but it automatically happens after every fresh deployment.

our process is kind of like this -

our system merged all similar files (lets say all css files) and all merged files are minified through jsmin and cssmin.rb through command line execution.

and store in a public directory, so our front reverse proxy server can serve them directly instead of knocking our application process.

since our server compression is enabled so we didn't need to worry about rest.

as you mentioned it gain some performance, we also believe so. since browser requires less connection to fetch all scripts.

as i see you have *aspx file which set the header and related stuffs. in our case we let our server do it for us(nginx). since we can configure server to serve different file and extension in different ways.

btw, thanks for bringing such an important topic.

# Regarding my previous post about problems in FF3

Monday, September 15, 2008 2:58 AM by Nikolay Raychev

I was pretty sure that there is somthing with encoding.

I made the following change:

   private byte[] GetFileBytes(HttpContext context, string virtualPath, Encoding encoding)

   {

       if (virtualPath.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))

       {

           using (WebClient client = new WebClient())

           {

               return client.DownloadData(virtualPath);

           }

       }

       else

       {

           string physicalPath = context.Server.MapPath(virtualPath);

           using ( MemoryStream stream = new MemoryStream() )

           {

               using ( StreamWriter writer = new StreamWriter( stream ) )

               {

                   string content = File.ReadAllText( physicalPath, encoding );

                   writer.Write( content );

                   writer.Flush();

                   return stream.ToArray();

               }

           }

           //byte[] bytes = File.ReadAllBytes(physicalPath);

           // TODO: Convert unicode files to specified encoding. For now, assuming

           // files are either ASCII or UTF8

           //return bytes;

       }

   }

Now the problem dissapeared.

I don't know why everybody tells that FireFox was a good browser. I'm always having problems exactly with Firefox and no other browser.

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Wednesday, September 17, 2008 6:29 AM by ASPdev

I have an asp.net application (no ajax though) where i currently pull data from a remote data server using normal sql command etc.

I pull all the required data once and keep it locally for future reads.

The web page communicates with the remote dataserver through a classic (xml) web service.

Since the call to retrieve data is taking time, the web application does not show the post back page quickly.

I want to move to a model where i can spawn an activity in the behind to gather the whole data in chunks while the page displays temporarily the "currently processing" message.

Would WCF help me here vis-a-vis xml web services "async" type calls?

Sorry if this question did not fit in well in this blog post, but i thought i will put it anyway since it is related to performance issue.

Thanks.

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Thursday, September 18, 2008 2:22 AM by omar

I suggest you use an IFRAME inside your main page that does the long running task. So, the postback happens on the IFRAME and the IFRAME takes a while to load. DUring this time, you can show progress bars on the parent page. When IFRAME loads, it can call functions on the parent page to disable the progress bar.

So, before post, inside the IFRAME, you call parent page to show some progress.

window.parent.showSomeProgress();

Here showSomeProgress() is a function on the parent page.

When the postback is complete, the iframe loads and calls:

window.parent.hideSomeProgress();

Again, this is a function on the parent page.

THe progress function can hide the IFRAME and show some animated progress bar in the same place.

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Thursday, September 25, 2008 10:21 AM by cibrax

Hi Omar,

The module does not work exactly how I expected. The browsers are not caching the content using the URL, they are basically sending a conditional get to the server with two headers "If-Modified-Since" and "If-None-Match", when the server returns a "304 Not Modified" code, then they used the cached version (Local). Otherwise they always download the file content from the server. You can repro the issue using the firebug pluggin in Firefox. Altough you serve the files content from the ASP.NET cache in the ashx handler, the browser is still hitting the server all the times and downloading the content, it is not using the cached version on the browser side, so the cache is only working server side. Thanks

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Thursday, September 25, 2008 6:39 PM by aswad32

hallo omar, thanks a lot for this kind of solution, you really help me, figure it out how i can improve my tons of javascript loading. you are great dude.

great from malaysia

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Tuesday, September 30, 2008 10:33 AM by Asrar Malik

It is too gooood

thans

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Tuesday, October 07, 2008 1:18 PM by Khurram Shehzad

Hi,

If you declare your theme in your configuration file the framework automatically registers all the css files inside theme folder. What could be done in this case without breaking the overall structure of the theme directory and implementation?

thanks in advance.

regards,

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Friday, October 10, 2008 4:12 PM by Dhruv

This doesnt work under medium trust apps. Is there a way to rectify that ?

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Tuesday, October 14, 2008 4:22 AM by kushin

For those who are getting errors in Safari/Chrome, that says:

Uncaught SyntaxError: Unexpected token ILLEGAL in the Chrome Inspector

As seen here: www.codeplex.com/.../View.aspx and here

www.mail-archive.com/.../msg01628.html

1. Make sure there are no illegal characters - trial and error - I put comments

  like //start of file1.js //end of file1.js

2. I also noticed that multi-line js comments like /* */ are no go when you plan to combine those files

  using the http-combiner.

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Tuesday, October 14, 2008 4:30 AM by kushin

Hi Omar,

In the HTTP-Combiner.zip file, I noticed that the t query-string is in the script tag is

mistyped as "t=type/javascript" instead of "t=text/javascript", not a big deal and the page still works but note to others who might use

Ctrl-C+Ctrl-V like me :D

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load problems in DNN

Wednesday, October 15, 2008 1:24 AM by ghbn

I use in Dotnetnuke and in home page is work good

but in other page not work!!!!!!!!

work only in Home page of portals

you can help me?

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load problems Page in sub folder

Wednesday, October 15, 2008 2:09 AM by ghbn

This cod have problem if your page in sub folder

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Saturday, October 18, 2008 10:24 PM by kushin

@ghbn: make sure you put the httpcombiner in the root folder and have it referenced /HttpCombiner.ashx

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Friday, November 07, 2008 5:12 AM by Hardik

Hi,

Whats the difference between HTTPCombiner and option we get in IIS under HTTP Headers - Enable Content Expiration ?

# Minify

Tuesday, November 25, 2008 1:07 PM by Steve Clay

If you have also have PHP5 installed, Minify is another (arguably) more mature and flexible option with the same goals/features as HttpCombiner.

@Hardik: "Enable Content Expiration" only sends the Expires/max-age headers with each request. This is a good first step but HttpCombiner/Minify also reduce the number and size of the requests.

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Thursday, February 12, 2009 8:00 PM by Kar

Hi Omar,

I got to this post because of some problem in IIS 6.0. Any why my handler is not receiving accept encoding header when the site was hosted on IIS 6.0.

Thanks.

# Javascript optimization in big web apps

Thursday, July 23, 2009 5:27 AM by GianfrancoTodini.com

Javascript optimization in big web apps

# hosting on cloud servers, medium trust problem

Thursday, December 31, 2009 2:34 AM by Amir

Dear Omar ,

I had a problem with uploading on medium trust servers , is there a way to change this ?

# re: HTTP handler to combine multiple files, cache and deliver compressed output for faster page load

Tuesday, January 12, 2010 8:27 AM by idan kepten

your sample is not working (all major browser)

for the CCS ... the p is not red for some reason

any help ?

Leave a Comment

(required) 
(required) 
(optional)
(required)