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 7×70 = 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:

You can reduce the wait time by using a CDN. 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 tag, you just put one < script> and one 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.

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 type="text/javascript" src="/Content/JScript/jDate.js">
<script type="text/javascript" src="/Content/JScript/jQuery.Core.js">
<script type="text/javascript" src="/Content/JScript/jQuery.Delegate.js">
<script type="text/javascript" src="/Content/JScript/jQuery.Validation.js">

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" >

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.

 

25 thoughts on “HTTP handler to combine multiple files, cache and deliver compressed output for faster page load”

  1. I believe Firefox is caching the main page and not seeing the new 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

  7. 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

  8. 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

  9. 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,

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

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

    Uncaught SyntaxError: Unexpected token ILLEGAL in the Chrome Inspector

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

    http://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.

  12. 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 😀

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

    This cod have problem if your page in sub folder

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

    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?

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

  16. Hi,

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

  17. 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.

  18. 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.

  19. hi i got a strange issue

    ie: i have been placed some styles on css ie:

    Some styles not working when i integrate the HTTPCOMBINER file

    but remaining styles are working – i do no wat the issue

    Let anyone give the idea for that.. ???

  20. Hello,

    Thanks for such a great post.

    I have followed the same steps that you have suggested. But some how the .css files are combines but it does not create any effect on my page. At a time any one css is applied. I have downloaded your sample project and found the same thing in that.

    Please help.

    Thanks,
    Nishant.

Leave a Reply