Skip to content
This repository

'Error loading page' when opening a page specified in appcache manifest (iPhone) #1579

Open
jammus opened this Issue May 06, 2011 · 46 comments
James Scott
jammus commented May 06, 2011

Supporting files: https://gist.github.com/959332

Steps to reproduce:

Open index.html on iPhone.
Click add to home screen.
Click on newly created icon.
Browse to 'read more'.

What should happen:

Otherpage.html should be loaded from the appcache.

What happens instead:

'Error loading page'.

Some googling has turned up this diagnosis from Stackoverflow: http://stackoverflow.com/questions/5824549/cannot-access-manifest-cached-files-with-ajax-from-webapp-saved-to-home-screen-in

"Apparently, when trying to use $.ajax() in offline mode, the request successfully fetches the cached files, but it returns 0 on XHMLHttpRequest.status. Having read up on this, I have seen that a status code of 0 can be returned when the user is offline and even when requesting local files. However, a successful GET should report a status code between 200 and 300. Perhaps $.ajax() checks for a 200-300 status, otherwise the request is considered to have failed."

Checking the value of jqXHR.responseText in the error handler of the ajax request shows the contents of otherpage.html.

The same issue also appears to affect Android (2.2 tested).

Kin Blas
jblas commented May 06, 2011

@jammus

What version of jQuery Core and jQuery Mobile are you using?

James Scott
jammus commented May 06, 2011

Sorry, my bad. jQuery 1.6 and jQM was built from master some time this morning.

Kin Blas
jblas commented May 06, 2011

@jammus: There were some problems with loading local files this morning that we've since fixed. Can you update and try the newer source?

James Scott
jammus commented May 06, 2011

@jblas: Sure thing. Done and reset the simulator - still getting the same issue on the iPhone. (Can't retest Android at the moment)

James Scott
jammus commented May 10, 2011

@jblas: Finally managed to retest on Android - still experiencing the same issue.

jcorporation

This is the same issue and the patch provided works for me with offline manifest
#926

James Scott
jammus commented May 13, 2011

@jcorporation: Thanks for the info. The issue is certainly similar. However the success callback isn't firing for me, only the error callback.

The line mentioned in the other ticket has since changed though so it maybe I'm looking in the wrong place.

jcorporation

Right, the line changed, you should try the patch. My symptom was an endless loading message.

James Scott
jammus commented May 14, 2011

The symptom here is the yellow 'Error loading page' message. The patch won't work in this case as the success callback of the ajax request in changePage is not called when loading a page stored in the appcache.

Kevin Hakanson

Looks similar to jQuery bug #8412. I wonder if an ajax prefilter that treats offline like other local protocols would work?

$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
  // treat offline like file: protocol
  if ( navigator.onLine && navigator.onLine === false ) {
    options.isLocal = true;
  }
});

Here is a snippet of the jQuery ajax code that would get triggered when isLocal is true and status is 0.

// If the request is local and we have data: assume a success
// (success with no data won't get notified, that's the best we
// can do given current implementations)
if ( !status && s.isLocal && !s.crossDomain ) {
    status = responses.text ? 200 : 404;
James Scott
jammus commented May 16, 2011

@hakanson Thanks for the link. That appears to be the exact issue we're experiencing.

The prefilter looks like a potential solution. I don't think navigator.onLine is the suitable value to check though as the appcache can be used even if the device is online. Under iOS navigator.standalone, which indicates if the site has been launched as a web app, is a better option. Not sure it's ideal though as there may be other circumstances where the appcache is hit.

James Scott
jammus commented May 16, 2011

Maybe applicationCache.status is a candidate. If it's not set to UNCACHED or OBSOLETE then apply the filter.

Kevin Hakanson

Is this the same issue as jquery/jquery-mobile#1194 from @mfkahn ? That also refers to jQuery bug #8412.

Kevin Hakanson

If appcache can be used when online, then navigator.onLine won't work.

Also, if appcache can be used either from Mobile Safari or if "webpage is displayed in full-screen mode" (Hiding Safari User Interface Components), then navigator.standalone won't work.

I agree that some property of DOMApplicationCache like applicationCache.status is better.

@jammus, can you try out an ajaxPrefilter and see if it works?

James Scott
jammus commented May 20, 2011

@hakanson Sure. After adding the following the 'error loading page' error is no longer shown and all pages load fine.

$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (applicationCache &&
            applicationCache.status != applicationCache.UNCACHED &&
            applicationCache.status != applicationCache.OBSOLETE
        ) {
        options.isLocal = true;
    }
});
James Scott
jammus commented May 20, 2011

Actually, it might not be working perfectly. Going back to it now I'm getting the same error as before but not every time. I'll do some more digging.

Michael Kahn
mfkahn commented May 30, 2011

See http://bugs.jquery.com/ticket/8412 , someone has posted a workaround that uses the 1.5.1+ isLocal setting for ajax. Seems to fix the issue, at least on iOS, I did not check android.

James Scott
jammus commented May 31, 2011

As a follow up to my previous comment the resurfacing of the error was due to entirely different issue so I'm now confident that the above fix works.

@mfkahn Thanks for the update. We earlier debated the use of navigator.standalone, however as the cache manifest can also be used in browser mode we weren't sure it was entirely suitable. Maybe the workaround should include both. I'll cross post to that ticket and see if anyone has more input.

Michael Kahn
mfkahn commented June 01, 2011

If it helps - on that ticket (http://bugs.jquery.com/ticket/8412) I had posted a link to the same issue I'd logged to ADC. The ADC issue report contains an example that can be used to demonstrate the issue. When I add the isLocal fix to the example the app works the same in both modes (web-app/browser). I was surprised, from reading the jquery docs I had assumed the isLocal setting would have fixed the items in the CACHE section but broken items in the NETWORK section, but it seems fine.

Todd Parker

Just following up here...is this still an open issue?

ksksks

This issue is still not solved and is a big problem.
Sites using ajax for loading stop working when a cache manifest is defined.
Wether the prefilter

$(document).ready(function () {
    $.ajaxPrefilter(function(options, originalOptions, jqXHR) {
        options.isLocal = true;
    });
});

nor a plain

$(document).ready(function () {
    jQuery.ajaxSetup({isLocal:true});
});

works for me on Android (GalaxyTab v2.2, Defy v2.3) or in Firefox 6.0.

Todd Parker

Just bumped up the priority here since it sounds like it's still unresolved.

John Bender

Doing my best to get caught up here and I have a few questions (bear with me):

@jammus

In your snippet

$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (applicationCache &&
            applicationCache.status != applicationCache.UNCACHED &&
            applicationCache.status != applicationCache.OBSOLETE
        ) {
        options.isLocal = true;
    }
});

won't this treat any and all requests as file system requests even when they aren't request to the cache or file system so long as the app cache is valid? So if the user is online, the cache is valid, and he/she makes a request for a page not listed in the manifest it really should be requested as normal (ie not isLocal). Again, I'm just eyeballing it so if I'm off course you'll have to forgive me.

@hakanson and @ksksks I would ask the same of both:

$(document).ready(function () {
    $.ajaxPrefilter(function(options, originalOptions, jqXHR) {
        options.isLocal = true;
    });
});

and

$(document).ready(function () {
    jQuery.ajaxSetup({isLocal:true});
});

isLocal appears to make sense when you can verify that the user cannot make web requests and should only be able to retrieve the material from the cache. If you look at the jquery xhr handling the reason this seems to work is that, right now, it only really cares about isLocal for coercing the status into something sane when the value is 0 and not cross domain.

https://github.com/jquery/jquery/blob/master/src/ajax/xhr.js#L167

John Bender

This is also probably a good place to note for people who read the above and want to use the workaround that if the request is cross domain it won't work. See (which @hakanson linked earlier):

https://github.com/jquery/jquery/blob/master/src/ajax/xhr.js#L167

John Bender

[edit] answered my own question with a simple test.

James Scott

Hi @johnbender,

Yeah, you're right. It treats all requests as local when a cache exists. As you point out though it is a bit of a hack. Maybe the check or one similar should be pushed into xhr.js in jQuery main rather than relying purely on isLocal behaving this way forever.

Cheers,
James

John Bender

Another quick update here:

http://dev.w3.org/html5/spec/offline.html#appcache

It looks like the manifest entries have to come from the same origin so my comment about cross domain requests not working shouldn't be an issue. I think the fact that isLocal really has nothing to do with the problem might prove dangerous since it could be used for other purposes in core.

tl;dr this will remain the workaround

Michael Kahn

Has anyone identified this an issue on any platforms except iOS running in navigator.standalone=true mode?

Adam Williams

I'm using the isLocal workaround.

I have index.html linking to welcome.html, welcome.html?v=1, and welcome.html?v=2. When I click on the first two, all's well! welcome.html is in the cache, and loads just fine, and my javascript can access the query param as undefined and 1, respectively. Yet when I click the third link, the xhr.status is 0, but the response.text is empty - therefore jQuery interprets this as a 404, and page load fails.

Why in the world would the first two links work fine, but not the third?

If I flip $.mobile.ajaxEnabled = false, then all three links work fine from the cache, but of course I lose page transitions.

This issue occurs in Safari 5.1.2. Chrome works fine, where any variance in query params still successfully loads welcome.html!

James Scott

@aiwilliams Do you have all three page in the cache manifest?

Adam Williams

No, I was not thinking of the v=1, v=2 as being separate pages, but I can see now that they are indeed treated that way by the cache mechanism. This seems to explain why $.mobile.ajaxEnabled = false causes the links to work, since each of the two query param urls would cause a fetch to the server. There are so many things to keep up with! I think I'm good to go.

Todd Parker

Sounds like we can close this issue then?

James Scott

@toddparker No, I don't think so. The original issue reported is different to the one @aiwilliams mentions here. At least as far as I understand.

John Bender

@toddparker

I concur with @jammus. We really want to leave this one open to signal to devs that it's still an outstanding issue and they need to use the workaround.

Todd Parker

Ok, sounds like a plan.

Matthew Berg

I recently came across this issue running Android 2.3.6. Any local pages just linked with index.html, about.html, dir/index.html all returned "Error loading page" when pulling from appcache.

So you have to choose between ajax and nice page transitions and offline capability? Seems like a pretty major issue right?

Nimmy
nimy commented April 17, 2012

I got offline cache downloading problem in Opera Mobile, it is not caching the files. Also getting window.applicationCache.status as always '0', when the 'turbo' setting is 'ON'. Unfortunately html5 storage (webSQL) is not working with 'turbo' 'OFF'. I need both (html5 offline caching & storage) to run my jQuery mobile application. Please help me.

PlippiePlop

This issue is still open with JQmobile 1.1 final and jQuery1.7.1

when using ajax for page navigation on Apple Iphone devices launching from homescreen (web-app)
It shows a error popup a second but continues to next page.

mdempfle

I can confirm this.
I have played around with different browsers and is seem that at the desktop Firefox and Chrome work fine. Also Opera on Android. It fails in the native browser of android 2.3.4 and Dolphin, Dolphin HD.

My current workaround is to use rel="external" for links.

So I agree with mattberg that this i a pretty major issue.

So is there a workaround where at least the ajax capability is not lost?

ryanmc2033

I am experiencing the same issue. Has a workaround or fix been developed for this? I am using JQM 1.1.0 and JQ 1.7.1, and I am all on the same domain.

Sven Franck

I'm also in the boat, although I don't use appache/manifest at all and still get the behavior described above.

Ryan Ilg

Also having this issue, running 1.2.0-alpha with jQuery 1.7.2

webslash

Can confirm this issue still exists.

Tested today on iPhone 5 (iOS6).
Exact same issue as @PlippiePlop

"Error Loading Page" shows for a second but the page does load.
Only happens when launching webapp from homescreen, works correct in safari.
Latest JQM version (1.2)

webslash

Currently I'm using this CSS snippet to move the error message out of screen:

.ui-loader.ui-body-e {
left:-9999px !important;
}

This is obviously far from perfect, but seems to be the only way to get rid of the error message within an iOS WebApp.

There's no loading image either so UX wise the user doesn't know a new page is loading..
(except for the tiny spinner in the iOS top bar)

Anyone with a proper solution, please share ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.