处理跨域JSONP调用的jQuery.ajax错误

14

我创建了一个ajax调用(jQuery 1.6.2)的测试用例,代码如下:

jQuery( document ).ready( function( $ ) {
    var test = function( x ) {
        $.ajax({
            url: 'http://www.someotherdomain.com/test.php',
            data: { x: x },
            dataType: 'jsonp',
            crossDomain: true,
            success: function( data ) { 
                console.log( data.name ); 
            },
            error: function() { 
                x++; 
                test( x ); 
            }
        });
    };
    test( 1 );
});

相应的test.php文件如下:

if ( 5 > $_GET[ 'x' ] ) {
    header('HTTP/1.1 503 Service Temporarily Unavailable'); die();
} else {
    header( 'content-type: application/x-javascript' );
    echo $_GET[ 'callback' ] . '({"name":"Morgan"})';
}

尽管jQuery文档显示jsonp调用的错误处理程序永远不会触发,但这个脚本按照我想要的方式工作。 它对test.php进行了四次“不成功”的调用,返回503错误,然后test()递归调用自身,将x增加,直到ajax调用“成功”,并将数据输出到控制台。

因此,我的上面的测试用例有效,但我的实际代码不起作用,它看起来更像下面的代码:

jQuery( document ).ready( function( $ ) {
    var completed = 0;
    var fiftystates; // assume an array of state objects
    var updateState = function( index, state ) {
        var d = index % 5; // for subdomains sub0, sub1, sub2, sub3, sub4
        $.ajax({
            url: 'http://sub' + d + '.mydomain.com/update_state.php',
            data: { state: state.id },
            dataType: 'jsonp',
            crossDomain: true,
            success: function() { 
                completed++; 
                var complete_percent = completed / fiftystates.length * 100;
                $( '#progressbar' ).progressbar( 'value', completed_percent );
            },
            error: function() {
                updateState( index, state );
            }
        }); // end ajax
    }; // end updateState
    $( fiftystates ).each( updateState );
};

正如您所看到的,这个循环遍历了5个不同的子域,实际上它们只是相同域名的镜像,但由于update_state.php可能需要长达30秒才能完成,这将需要25分钟的过程缩短到不到三分钟。问题在于服务器负载导致一些ajax请求失败,并返回503错误。在我的测试用例中,处理这个问题没有问题,但在我的第二个示例中,错误处理程序似乎永远没有被调用。

我想不出为什么测试用例按照我的期望工作而第二个示例却不行。有什么想法吗?


尝试更改到jQuery 1.6.4,但结果相同。 - morphatic
使用PHP的header()返回503状态码与“实际”的503状态码是否有所不同?我检查了两种情况下的HTTP头,它们在我的看来是相同的... - morphatic
在你的第一个例子中,你在错误处理程序中每次都会增加x(x++;)。在你的第二个例子中,你没有增加index++;这是我能看到的唯一明显的区别。 - Kato
另外,您是否尝试过在没有die()命令的情况下进行503测试?这可能会阻止添加其他服务器标头,从而导致在第二种情况下使用成功。 - Kato
另外,你的头部调用应该像这样吗?header("HTTP/1.0 503 Service Temporarily Unavailabel", true, 503);也许这会导致它们表现不同?在这里查看更多想法:https://dev59.com/GnE85IYBdhLWcg3wejZO(好的,我现在走了 :)) - Kato
4个回答

4

应该按照这种格式吗:

$.ajax({
    type: "POST",
    url: 'http://servername/WebService.svc/GetData?callback=?',
    dataType: 'jsonp',
    success: function (data) {
       //do stuff
    },
    error: function (msg, b, c) {
    //alert error
    }
 });

JSONP不能用于跨域进行POST请求。jQuery会自动将其更改为GET请求。 - cesarislaw
3
请检查jQuery官网:“注意:此处理程序不适用于跨域脚本和跨域JSONP请求。” - shereifhawary

3

在你的测试用例中,每次调用都会更改x的值...

在其他代码中,您发送了相同的索引值。这将返回相同的结果,而不是“旋转”子域...

    error: function() {
        index++;
        updateState( index, state );
    }

1
索引参数会在 jQuery.each() 函数调用的倒数第二行自动递增。这是个好想法,但我不认为那是问题所在。 - morphatic
我知道索引会在.each()函数调用时改变。但是这并不影响在错误情况下调用的索引。对于数组中的每个状态,您都会调用该函数,如果出现错误,则会调用自身... - blindfold

3
如果您在第一种情况下使用IE测试,而在第二种情况下可能使用FF或Chrome进行测试,则可能是原因。如jQuery.ajax函数所述,交叉域JSON / JSONP类型不会调用错误和全局回调。但是,我注意到它们仍将在IE中被调用,我认为这与jQuery使用IE XMLHttpRequest执行调用有关。
似乎有人慷慨地创建了一个插件,处理可用的JSONP请求错误,网址在此处:http://code.google.com/p/jquery-jsonp/

1
function AjaxRequest(url, params){

    return $.ajax({
        url:            url,
        data:           params,
        dataType:       'jsonp',

        /* Very important */
        contentType:    'application/json',
    });
}

var test = function(x) {

    AjaxFeed('http://servername/WebService.svc/GetData', {x: x})

    /* Everything worked okay. Hooray */
    .done(function(data){

        console.log(data);
    })

    /* Oops */
    .fail(function(jqXHR, sStatus, oError) {

        console.log(arguments);
    });
}

jQuery(window).load(function() {

    test('test');
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接