Page 1 of 1

Client side 404 error detection for images

Posted: Wed Jul 18, 2012 5:22 pm
by Benjamin
I need to build a solution that will detect when images receive a 404 error response. Even if an image does load, the HTTP response code may still be a 404 Not Found. After the page has completely loaded, I need to gather an array of all paths to images that returned a 404 response code and submit them back to my server via ajax.

Any clues how this can be done?

Re: Client side 404 error detection for images

Posted: Wed Jul 18, 2012 7:14 pm
by Weirdan
something like this could work if put into document head:

Code: Select all

// experiment with this at http://jsfiddle.net/9ttmJ/
var images = document.get​ElementsByTagName('img')​​​​;
var failedImages = [];
for (var i = 0, l = images.length; i < l; i++) {
    images[i].onerror = function() {
        failedImages.push(this);     
    }​;
}
$(window).load(function() {
    console.log(failedImages);
});
​

Re: Client side 404 error detection for images

Posted: Thu Jul 19, 2012 12:09 am
by Benjamin
Yeah I saw a similar solution while searching. I tested that, but onerror is null because an image is being returned. Even though an image exists, what I need to detect is the actual 404 Not Found header.

Re: Client side 404 error detection for images

Posted: Thu Jul 19, 2012 6:23 am
by Weirdan
Another alternative that I could think of would be not really checking if an image is loaded, but do a second request (probably HEAD) to the src url, assuming it's unlikely that image was added or removed inbetween two requests. If image is cached by the browser unconditionally it might be even better to do full GET request and expect browser to serve it from cache with all the headers you need.
Even though an image exists, what I need to detect is the actual 404 Not Found header.
Do you have public examples of such urls I could use for testing?

Re: Client side 404 error detection for images

Posted: Thu Jul 19, 2012 6:52 am
by Weirdan
Seems to be working, but can't work cross-domain

Code: Select all

// http://jsfiddle.net/SRvqN/1/
$(window).load(function() {
    $('img').each(function() {
        var url = $(this).attr("src");
        $.ajax(url, {
            cache: true,
            statusCode: {
                404 : function() {
                    $('table').append('<tr><td>' + url + '</td></tr>');
                }
            }
        });
    });
});

Re: Client side 404 error detection for images

Posted: Thu Jul 19, 2012 6:59 am
by Benjamin
I was just going to mention that I was going to try ajax but figured it wouldn't work across domains. These images will also be lazy loaded so I thought why not lazy load them via ajax and test them at the same time. I'm not sure this is possible.

Here's code that will generate something very close to what is being sent.

Code: Select all

<?php
header("Status: HTTP/1.1 404 Not Found");
header("Date: Fri, 13 Jul 2012 17:42:27 GMT"); # current timestamp
header("Expires: Fri, 13 Jul 2012 17:42:57 GMT");
header("Cache-Control: public, max-age=30");
header('Content-Length: 168');
header('Content-Type: image/png');
header("Connection: close");

$image = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAAlwS'
        .'FlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wHEwswBfrdfwgAAAAidEVYdENvbW1lbnQAQ3'
        .'JlYXRlZCB3aXRoIEdJTVAgb24gYSBNYWOHqHdDAAAADElEQVQI12P4//8/AAX+Av7czFn'
        .'nAAAAAElFTkSuQmCC';

echo base64_decode($image);

Re: Client side 404 error detection for images

Posted: Thu Jul 19, 2012 9:33 am
by Weirdan
Lazy load them via ajax and test them at the same time. I'm not sure this is possible.
It's possible, but I'm not sure it's 100% cross-browser. For IE you would have to add JS implementation of btoa() (Base64 encoder):

Code: Select all

<html>
<head>
    <script src="jQuery/jquery.js"></script>
    <script>
        $(function() {
            $('img').each(function() {
                var elt = $(this);
                var url = elt.attr('data-src');
                $.ajax(url, {
                    cache: true,
                    beforeSend: function(jqXHR) {
                        jqXHR.overrideMimeType("text/plain; charset=x-user-defined");
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        $('body').append("<br>failed to load:" + url);
                    },
                    success: function(data, textStatus, jqXHR) {
                        console.log(data.length);
                        var d = "";
                        for (var i = 0, l = data.length; i < l; i++) {
                            d += String.fromCharCode(data.charCodeAt(i) & 0xff);
                        }
                        elt.attr("src", "data:image/png;base64," + btoa(d));
                    }
                });
            });
        });
    </script>
</head>
<body>                                                                                                                                  
<img data-src="img.php"/>                                                                                                               
<img data-src="exists.jpg"/>                                                                                                            
</body>                                                                                                                                 
</html>                         
The trick is to override mime type so browser would think it's 8bit and post-process received data stripping everything but lowest byte.

Re: Client side 404 error detection for images

Posted: Thu Jul 19, 2012 2:32 pm
by Benjamin
Thank you. It doesn't have to work in all browsers. I will run some tests on this.