Fail callback called although Ajax request is performed and server returns 200 with data
Asked Answered
B

4

7

I have a HTML5 test webpage test.html with a cache manifest. The webpage does an Ajax request to the same server, to a webpage do_get_data.php that is listed under the section NETWORK: in the cache manifest.

The request is performed by both Firefox 10 and iPhone iOS 5 Safari (this is logged in the serving PHP script do_get_data.php). Firefox 10 calls the success callback function after 10 seconds, that is, when data from the server is returned. However, my iPhone iOS 5 Safari calls the fail callback function immediately after it started the request and doesn't call the success callback function.

For iPhone iOS 5 Safari, the textStatus is error and JSON.stringify(jqXHR) is {"readyState":0,"responseText":"","status":0,"statusText":"error"}.

The request is performed using the following code in test.html:

<script type="text/javascript">
    function test_ok(data) {
        alert('Test OK, data: ' + JSON.stringify(data));
    }
    function testFail(jqXHR, textStatus) {
        alert(textStatus + ' | ' + JSON.stringify(jqXHR));
    }
    function get_data(testurl) {
        var senddata, request;
        alert('Request for ' + testurl + ' started.');
        window.testid = new Date().getTime();
        senddata = {
            background: true,
            requestId: window.testid
        };
        request = $.ajax({
            url: testurl,
            cache: false,
            type: "GET",
            data: senddata,
            success: test_ok
        });
        request.fail(testFail);
    }
</script>
<input type="button" onclick="get_data('do_get_data.php')" value="test sending" />

For reference, do_get_data.php looks like this:

<?php
    $id = md5(rand() . rand());
    trigger_error(implode("\t", array('start', $id, $_SERVER['REQUEST_URI'], $_SERVER['REMOTE_ADDR'], $_SERVER['USER_AGENT']));
    sleep(10);
    header('Content-Type: application/json');
    $json = json_encode(array('msg'=>'Test was OK'));
    trigger_error(implode("\t", array('echo', $id, $json));
    echo $json;
?>
Bascom answered 24/2, 2012 at 12:7 Comment(7)
What happens if you remove sleep(10) ?Bless
And do I understand it correctly that you have a log that shows successful requests from Safari on the server side?Bless
@asaddude Even if I remove sleep(10), the situation is the same. Yes, the log on the server side shows Safari.Bascom
I see you use a hybrid definition of AJAX callbacks - new way (jqXHR.fail()) and the old way (success option of $.ajax()). Is there a particular reason for the combination? Does it yield same results when jqXHR.done() or error option respectively is used instead?Markland
@Petr There is no good reason for the combination. However, done() or error option do unfortunately not change the fact that it works in Firefox but not iOS 5 Safari.Bascom
OK. To narrow it down more, and I realize the following wouldn't be a "solution", but what happens if you disable the manifest?Markland
@Petr Vostrel It is not an optimal solution, but it DOES work when disabling the manifest and is an okay workaround until I find the real culprit.Bascom
M
2

I've been given to understand, that causes of status code 0 are (1) loading from file://, (2) unreachable network resource and (3) cross domain policy. Since you load PHP, we can safely rule number 1 and since your server logs Safari also the number 2 too, which leaves us with 3. Does all of the above code sit on the same domain? If not, use the Access-Control-Allow-Origin HTTP header in the PHP to allow cross domain requests.

header('Access-Control-Allow-Origin: http://example.org')

Also, you should make sure, the click on the button input performs only the onclick and not any other default behavior (whatever that may be on the iOS). Returning false from the onclick handler would prevent it:

<input type="button" onclick="get_data('do_get_data.php'); return false" ... />

UPDATE:

As a last resort you can always simply disable the cache manifest to move its maybe buggy implementation out of the way.

Markland answered 2/3, 2012 at 13:3 Comment(4)
Thank you very much for your answer. I like your reasoning. Theoretically, I agree it might be a cross domain policy problem. However, it is on the very same domain. http:// is not even used for the URL, but instead do_get_data.php without any domain name. Is there a good way to debug this problem? Returning false did actually not change anything.Bascom
Unfortunately, the debugging facilities are very poor on iOS and mobile devices in general... When doing my research, I also stumbled onto related mentions, where relative path was identified as the cause. Have you tried absolute URL path? And to clarify - does the problem persist without the cache manifest?Markland
However, using disabling the manifest as you proposed in your earlier comment. This is an okay workaround until I find the real culprit. I will give you the bounty provided no one else solves the main problem, if you just copy your comment to a new answer, or including your comment in this answer.Bascom
@Richard86 I've updated the answer and I'm happy it kills the pain for you. However, since we have it somehow isolated now, out of curiosity, how does your cache manifest look like?Markland
T
2

I have struggled with this for a while and the answer was in the bug report answers:

use

NETWORK: *

in the cache manifest to avoid caching the ajax request too.

Tabethatabib answered 10/7, 2014 at 22:24 Comment(0)
V
1

What if you change your $.ajax call to

$.ajax({
    url: testurl,
    cache: false,
    type: "GET",
    data: senddata
}).then(
    function(result) { test_ok(result); },
    function(result) { testFail(result); }
);
Venture answered 2/3, 2012 at 3:50 Comment(2)
Thank you for your answer. Unfortunately, this does not solve the problem. It still results in a request, but testFail() is called.Bascom
What happens if you remove the Content-Type header in your PHP code? Maybe Safari is having an issue with that. In all the AJAX code I've ever written, I've never set a Content-Type header. I just echo the plain text.Venture
V
1

Not sure how you are running your site under iOS, but there's been an issue with jQuery and AJAX requests while using manifest files: http://bugs.jquery.com/ticket/8412

Although you are already listing the resource under the NETWORK section of the manifest, I would suggest trying out the other workaround listed there:

jQuery.ajaxSetup({
  isLocal: true
});
Virga answered 4/3, 2012 at 3:25 Comment(1)
Thank you for new thoughts on the problem. It seems that the ticket actually returns the correct content, which is not the case for me. The request is actually done live to the server. I tried with isLocal: true but unfortunately this did not solve the problem. The same error exists.Bascom

© 2022 - 2024 — McMap. All rights reserved.