17

I am loading a user-selected page into an iframe using the src property. If the load fails, I would like to report the problem in terms that will make sense to the user. iframe does not, in general, support onerror according to http://www.w3schools.com/jsref/dom_obj_frame.asp.

The page may come from the user's domain, not mine, so I cannot view the content of the iframe.

I can set a timeout and cancel it from my onload handler if the load is successful, but it would need to be a long timeout to avoid false error reports, and meanwhile Safari on my iPhone has displayed an alert that may confuse the user. Even this does not work for the Kindle Fire browser - it delivers a load event to my handler regardless of whether the load was successful.

Is there any event I can use to detect failure? Is there any way to suppress the default Safari behavior? Any way I can tell whether the load attempt has failed? (If I could do that, I could use a shorter timeout and poll until the load attempt is resolved).

I can require the use of up to date browsers, but would like a solution that is portable among as many smartphones and tablets as possible.

I have tested the AJAX Get idea, and it unfortunately does not work. A cross-domain AJAX Get to an arbitrary URI results in an exception, regardless of whether the target exists and can be loaded into the iframe or not.

Patricia Shanahan
  • 24,883
  • 2
  • 34
  • 68
  • I realize this may not be possible. If nobody posts a solution that lets me do what I want to do, I plan to award the bounty to clearest, best documented explanation resolving the issue by showing it is impossible. – Patricia Shanahan Nov 07 '12 at 10:31

3 Answers3

10

You could set your iframe and/or ajax request to always call a page you control (ie: loader.php), sending loader.php the user's requested page via get. From loader.php, use curl or even just file_get_contents to fetch the external page. If the request fails to come back to loader.php, you can check the error there, and return whatever you want your iframe to display.

While my example references the use of php, curl is supported in a variety of scripting languages. It is likely more complicated than other solutions you might have, but would give you access to the response headers as well for troubleshooting why a page load failed.

RelicScoth
  • 697
  • 4
  • 18
  • Sounds promising. I'll try it out. – Patricia Shanahan Nov 08 '12 at 05:33
  • 1
    In an article it was called [a Web Proxy](http://developer.yahoo.com/javascript/howto-proxy.html). If you do this you may [want to consider whitelisting](http://christianheilmann.com/2010/01/10/loading-external-content-with-ajax-using-jquery-and-yql/) the domains. – surfmuggle Nov 11 '12 at 23:05
  • I believe there will be a solution along these lines, and it is getting to the end of the current bounty period, so I've decided to award it the bounty. However, it is not a complete solution to my problem, and I'm still looking for ideas, so I have not accepted an answer. – Patricia Shanahan Nov 13 '12 at 03:31
  • Thank you! Have you had an opportunity to test the approach yet? If so, what did you run into? – RelicScoth Nov 13 '12 at 13:51
2

As you've hinted, you'll face same-origin-policy type restrictions when you try to query anything inside the iframe if it's on a separate domain.

You could make an AJAX GET request to the iframe's URL before you pass it into the src of the frame. If you don't get an HTTP 200 response back from the AJAX call, then the site won't be able to load inside the frame either.

This will add overhead to the whole process, and is only useful if you're checking whether the iframe's document is a real URL that works. It won't help if you need to know when the iframe document has fully loaded.

If you need to know when the iframe has loaded, and it's on an external domain, then I believe you have no other option but to ask for some code to be added to those external sites to notify the parent page that they've loaded successfully.

Or, if it makes sense to do so, ask the end user to click a link to flag up that the content isn't loading correctly.

Aaron Pollock
  • 429
  • 5
  • 13
  • The pre-test is an interesting idea. I'll try it out. If the load is successful there is no problem. iframe does support onload, and all the browsers I've tried so far call my onload handler on successful load. – Patricia Shanahan Nov 05 '12 at 00:29
  • I just had another thought. Maybe I could start the iframe load first, then wait a short time. If I get the onload before the timeout, all is well. If not, try the AJAX GET test, report failure if it fails, go back to waiting for a longer time if it succeeds. That would be as fast as possible for the normal case in which the page loads quickly. The downside is I would still get the Safari alert on failure. – Patricia Shanahan Nov 05 '12 at 00:50
  • Yes, that'll answer the question, "Is it down/missing, or is it just very slow?" – Aaron Pollock Nov 05 '12 at 00:55
  • Unfortunately, it does not work because of the cross-domain issue. I get an exception on the send call. At least on Safari, the exception is the same regardless of whether the target exists or not. Good try. – Patricia Shanahan Nov 05 '12 at 03:43
-1

Late to the party, but I've managed to crack it:

At first, I thought to do an AJAX call like everyone else, except that it didn't work for me initially, as I had used jQuery. It works perfectly if you do a XMLHttpRequest:

var url = http://url_to_test.com/
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status != 200) {
        console.log("iframe failed to load");
    }
};
xhttp.open("GET", url, true);
xhttp.send();

Edit:
So this method works ok, except that it has a lot of false negatives (picks up a lot of stuff that would display in an iframe) due to cross-origin malarky. The way that I got around this was to do a CURL/Web request on a server, and then check the response headers for a) if the website exists, and b) if the headers had set x-frame-options.

This isn't a problem if you run your own webserver, as you can make your own api call for it.

My implementation in node.js:

app.get('/iframetest',function(req,res){ //Call using /iframetest?url=url - needs to be stripped of http:// or https://
   var url = req.query.url; 
    var request = require('https').request({host: url}, function(response){ //This does an https request - require('http') if you want to do a http request
        var headers = response.headers;
        if (typeof headers["x-frame-options"] != 'undefined') {
            res.send(false); //Headers don't allow iframe
        } else {
            res.send(true); //Headers don't disallow iframe
        }
    });
    request.on('error',function(e){
       res.send(false); //website unavailable
    });
    request.end();
});
immanis
  • 50
  • 1
  • 5
  • I have abandoned the project that inspired this question. However, I will do some tests over the next couple of weeks and report results. – Patricia Shanahan Aug 23 '17 at 07:32