3

It appears that the HEAD requests I'm sending via jQuery's $.ajax({...}); method, are returning the content of the given resource (at least in Firefox... IE appears to function normally), rather than just headers. I'm trying to capture only the Content-Length header property, for use in an image preloader, though it seems that by merely querying for the Content-Length, it's downloaded the content itself.

The order of operation here, is:

  • Find all elements in a given page with CSS background-image, and populate an array (imageTemp) with the URLs.
  • For each image URL, perform an Ajax HEAD request, to obtain the Content-Length and add that to bytesTotal as well as populate the array (imageData) with both the URL and that image's Content-Length.
    • Simultaneously, start a setInterval event handler to periodically check whether or not all of the Ajax HEAD requests have completed.
  • When the HEAD requests have completed, begin loading the images into Image() objects from imageData, adding the associated image Content-Length value to the bytesLoaded value.\
  • When bytesLoaded == bytesTotal images are done loading, and the preloader has completed.

Here is my script as of currently:

(function($){

    var callbacks = {
        initiate: function(){},
        progress: function(percent){},
        complete: function(){},
    };

    var imageTemp = Array();
    var imageData = Array();
    var imageCurrent = null;
    var intervalId = 0;
    var bytesLoaded = 0;
    var bytesTotal = 0;

    $.preloader = function(arguments){

        for(var arg in arguments){
            callbacks[arg] = arguments[arg];
        }

        callbacks.initiate();
        $('*')
            .each(function(index){
                if($(this).css('background-image') != 'none'){
                    imageTemp.push($(this).css('background-image').slice(5, -2));
                }
            });

        intervalId = window.setInterval(function(e){

            if(imageData.length == imageTemp.length){
                window.clearInterval(intervalId);

                for(var i = 0; i < imageData.length; i++){

                    (function(imageIndex){
                        currentImage = new Image();
                        currentImage.src = imageData[imageIndex][0];
                        currentImage.onload = function(e){
                            bytesLoaded += parseInt(imageData[imageIndex][1]);
                            callbacks.progress(bytesLoaded/bytesTotal);
                            if(bytesLoaded >= bytesTotal){
                                callbacks.complete();
                            }
                        };
                    })(i);

                }

            }

        }, 1);

        for(var i = 0; i < imageTemp.length; i++){
            (function(i){
                $.ajax({
                    type: "HEAD",
                    async: true,
                    url: imageTemp[i],
                    success: function(message, text, response){
                        var bytes = parseInt(response.getResponseHeader('Content-Length'));
                        bytesTotal += bytes;
                        imageData.push([imageTemp[i], bytes]);
                    },
                });
            })(i);
        }

    };

})(jQuery);

This is directly associated with my question over at Ajax HEAD request via Javascript/jQuery, but it certainly not a duplicate, as the issue has extended from the previously solved question.

Community
  • 1
  • 1
Dan Lugg
  • 20,192
  • 19
  • 110
  • 174
  • 2
    If the request is going out properly, and you're getting back more than just the HTTP response header, wouldn't that mean that it's a server problem? IE may just be ignoring the response body. What happens when you hit your URL with "wget" or "curl"? – Pointy Jan 17 '11 at 20:42
  • **@Pointy**; Haven't tried, don't have cURL installed. My only reasoning for this, is that the preloader hangs on `initiate` until it is entirely complete, and then skips to `complete`, tosses out `100%`, and the preloader is done. There is no progression. Whereas in IE, it is acting normally; as images download, the percentage goes up. I suppose I'll have to give cURL or something a try.. Any other ideas? – Dan Lugg Jan 17 '11 at 20:57
  • 1
    To help debug this, look at the http request in detail. I recommend livehttpheaders extension for firefox. You should see something like `HEAD /image.gif` if the javascript & browser are acting correctly. Be aware, you will see `GET /image.gif` if the browser is requesting the image on its own(after it found an element or css rule etc..), so you may see both types of requests. – goat Jan 17 '11 at 21:19
  • maybe i'm tired, but... how do you prevent the browser to perform the real GET request from the css? – regilero Jan 17 '11 at 21:47
  • @regilero, I think browsers will request external resources(eg, an image) defined in css once the browser is sure the style rule will need to actually be applied. So either don't give it the css rule, or maybe do some trick with a descendant selector that won't match until js modifies the dom. – goat Jan 17 '11 at 22:18
  • Thanks to **chris** and **regilero**; Using Firebug, I can see the response in detail, and content appears to be available. Also, if I `console.log()` part of the xmlHttp response (I forget what exactly, haven't looked at it in a bit) from the `HEAD` request, it dumps the raw image data. This suggest to me, that Firefox isn't interpreting my `HEAD` request properly. I've seen articles make mention of certain request methods not being implemented to standard, even in prominent browsers. Though often minor details, perhaps this is a case where the issue is causing effect. – Dan Lugg Jan 19 '11 at 02:58

2 Answers2

2

I encourage you to set up Fiddler (or some other HTTP packet sniffer) and see what is actually going through the wire - exact requests sent and exact response received. This will help you troubleshoot whether the problem is on the server or the client.

Alex Weinstein
  • 9,823
  • 9
  • 42
  • 59
  • Thanks **Alex**; This appears to be the route I'll have to take for debugging this. As of now, I've decided to put the completion on hiatus in favor of more important projects. The browser compatibility of this entire idea in practice is terrible at best, mind you I haven't taken many precautions, I just want it to work *somewhere* before I bother with compatibility. I looked briefly into Fiddler, it seems pretty comprehensive; I'll grab it shortly :) – Dan Lugg Jan 19 '11 at 02:53
1

Well it looks weird. This "should" work.

I cant say for sure this is the problem but maby it is so here I go:

If you do a HEAD request the server itself shouldnt you send you more than the head data. Almost every webserver you can get out there honors this.

So the chances of a server issue is unlikely. However its possible, depending on the application running.

But I have seen this very issue a lot of times in in many crawling environments and stuff, and a very common point of failures were redirects.

A lot of internal libraries follow redirects (as they should) but "forget" about the HEAD request.

I once looked up the RFC but couldn't quite figure out what exactly should be done at this point.

But very strictly interpreted the HEAD request should give you the Location header.

But most "users" probably expect the head data of whatever is behind the redirect.

For example Zend ZF has this issue up til today. scrapy fixed it some later release.

Sorry I can't give you a better answer but your code looks correct regarding this issue so its some trial and error debugging...

The Surrican
  • 29,118
  • 24
  • 122
  • 168
  • Thanks **Joe Hopfgartner**; It cannot be redirects, as I'm targeting static content. There seems to be a lot of inconsistencies across browsers for handling `HEAD` requests, regardless of the server architecture it appears. I suppose I'll have to keep digging, I'm still a bit new when it comes to understanding HTTP requests at a lower level, but I'll work through it. Thanks for the information :) – Dan Lugg Jan 19 '11 at 02:49