15

I'm loading images from a server which returns images when there is a 404. That is, if the image I'm loading doesn't exist, the server will return a 404 response with a 200x200 PNG fallback image that says "photo not available" on it.

I would like to detect the times when this happens client-side. I tried the onerror attribute:

<img src="http://example.com/photo.jpg" onerror="console.log(this)" />

This code only works when the 404 response from the server has no image at all. Since my 404 response does, the onerror event is never fired.

Is there a way around this problem, short of pre-loading images with JavaScript?

Brad
  • 159,648
  • 54
  • 349
  • 530
  • If the `onerror` handler doesn't work, you could do a head request to the url's and check for a 404 – adeneo Feb 26 '15 at 20:06
  • Pinging the URL inside of JavaScript and checking the response code? – Lloyd Banks Feb 26 '15 at 20:07
  • Yes, those are options I will resort to if I cannot find a better way. I'd much prefer a different solution so I can leave the images in the markup for non-JavaScript users. – Brad Feb 26 '15 at 20:10

5 Answers5

1

(Updated, as @Brad pointed out the obvious details I was ignorant to.)

I stumbled across this which seems to trigger the onerror() properly:

<html>
    <head>
        <script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
        <script type="text/javascript">
        (function($) {
            $.fn.errimg = function(options) {
                return this.each(function() {
                    if (this.tagName.toLowerCase() != 'img')
                        return;         

                    // store current img for error reference
                    var $_orig = $(this);
                    // create "production" image
                    var $newImg = $_orig.clone()
                        .attr('src', $_orig.data('src') || '')
                        .one('error', function() {
                            $(this).parent()
                                .empty()
                                .append($_orig);
                        });
                    // replace current img
                    $_orig.parent().empty().append($newImg);
                });
            };
        })(jQuery);         

        $(function() {
            $('.js_img img').errimg();
        });
        </script>
    </head> 

    <body class="js_img">
        <img id="testimgbad" src="http://img4.homefinder.com/i/00000000-0000-0000-0000-000000000000/w200-h-q" onerror="console.log('errored out');" />
    </body> 

</html>
Patrick Webster
  • 290
  • 1
  • 7
  • That's simply not true. You definitely can send data back with a 404, and this is very commonly done. 404 is the correct response status code in my case, and the image returned is as-designed. I just need to detect it client-side for a particular application. – Brad Mar 01 '15 at 14:35
  • Can you give me a link where this occurs? I'm not suggesting you're wrong, I've just never had, or more accurately *witnessed* a browser knowingly do this. – Patrick Webster Mar 01 '15 at 14:36
  • http://img4.homefinder.com/i/00000000-0000-0000-0000-000000000000/w200-h-q It's also pretty common for images removed from image hosting sites, forums, and for sites that disallow cross-linking (although for cross linking they usually send a 403 with the image). – Brad Mar 01 '15 at 14:39
  • @Brad thank you for taking the time/patience to point that out, I had never seen that until now. Response updated. I'm really curious how/why that could happen in the first place, but admittedly most of my time is spent with very strange, low level work usually involving editing the server software itself, not the content / pages / files being served. – Patrick Webster Mar 01 '15 at 15:08
  • Think of it like any other error document. People use custom 404 pages all the time. This is no different, other than that the content type is specialized. You see similar things on JSON API servers where a nice JSON error response is sent rather than an HTML 404 page. – Brad Mar 01 '15 at 15:11
  • Yea, I was just reading the specs about this after posting the above. Since the browser has to read ahead to find out the content type that was sent to render the image, it can't bail out per a normal 404, and thus the status error is ignored. I really hope http2 manages to suss out the niche case exceptions that have come from developing browsers for 2015 based on standards from 1999. It still seems like there should be another way to access that status though, possibly with the DOM shadow elements. Let me see what else I can conjur up to save doing a copy for every image loaded. – Patrick Webster Mar 01 '15 at 15:18
  • [this isn't a new thing](https://bugzilla.mozilla.org/show_bug.cgi?id=299138) after all :) – Patrick Webster Mar 01 '15 at 15:19
  • It's a perfectly fine use case for HTTP/1.0. And, the browser does throw an error as I can see it in my console. It just doesn't fire the `onerror` for the image, which I agree is a bug but a very consistent bug across a few browsers. The reason I added a bounty on the related question was that I think a workaround may be to catch all errors (just like the developer tools do) and then search the DOM to remove the offending image elements with the matching `src` attribute. Someone else posted a solution for this, I just haven't tested it yet. – Brad Mar 01 '15 at 15:36
0

One solution is NOT to return an image when the intended image is not found on the server. Instead, the error image is displayed later using the onerror event.

<img src="tttttttt.png" onerror="this.onerror=null;this.src='https://www.google.com/images/srpr/logo11w.png'" />

JSFiddle

Reference: jQuery/JavaScript to replace broken images

Community
  • 1
  • 1
Oday Fraiwan
  • 1,147
  • 1
  • 9
  • 21
  • This isn't an option for me, as the service is used elsewhere in addition to my application, and needs to return 404 images in other cases. – Brad Feb 26 '15 at 20:56
0

The workaround I took is calling an internal method trough ajax that check with a httpclient if the image is returning a 404 premade page. If so (any status 404), then returns my own anonymous image, if not, returns the string itself.

Leandro Bardelli
  • 10,561
  • 15
  • 79
  • 116
-1

U might use onload function instead of onerror, and check for the image loaded (if you know something about that image at the beginning).

You might as well messure how many times do you expect this to happen, since your're registering some kind of listener for every possible image that might be unnecesary.

Janx from Venezuela
  • 1,147
  • 1
  • 10
  • 12
-1

If you are sure the dimensions differ between an existing image and a 404-image, you could use that information to do some other trick.

For example you want to the show the biggest 16:9 Youtube thumbnail available. Youtube returns a 120px by 90px '404-image' if the fetched thumbnail does not exist. So let's fetch the maxresdefault thumbnail and show an mqdefault thumbnail as fallback:

<img src="https://img.youtube.com/vi/{id}/maxresdefault.jpg" onload="if (this.naturalWidth === 120) {this.src = this.currentSrc.replace('maxresdefault', 'mqdefault');}">
Jacob van Lingen
  • 8,989
  • 7
  • 48
  • 78