【问题标题】:handling jQuery.ajax errors for cross-domain jsonp calls处理跨域 jsonp 调用的 jQuery.ajax 错误
【发布时间】:2011-12-02 18:13:45
【问题描述】:

我构建了一个 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 documentation 表示永远不会触发 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,结果相同
  • 可能是使用 php header() 返回 503 的行为与“实际”503 不同吗?我检查了这两种情况的 HTTP 标头,它们看起来和我一模一样...
  • 在您的第一个示例中,您在错误处理程序中每次 (x++;) 递增 x。在您的第二个中,您不会增加 index++;这是我能看到的唯一明显区别。
  • 另外,您是否尝试过不使用 die() 命令的 503 测试?这是否会阻止添加其他服务器标头,从而导致它在第二种情况下利用成功?
  • 另外,你的标题调用不应该是这样的吗? header("HTTP/1.0 503 服务暂时不可用", true, 503);也许这导致他们的行为不同?更多想法请看这里:stackoverflow.com/questions/2760884/…(好吧,我现在去:))

标签: jquery ajax error-handling cross-domain jsonp


【解决方案1】:

在您的测试用例中,您每次调用都会更改值 x für...

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

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

【讨论】:

  • index 参数由倒数第二行的 jQuery.each() 函数调用自动递增。好主意,但我认为这不是问题所在。
  • 我知道索引是由 .each() 函数调用更改的。仍然不会影响在错误情况下调用的索引。对于数组中的每个状态,您都调用该函数,该函数会在发生错误时调用自身...
【解决方案2】:

如果您偶然使用 IE 来测试第一种情况,并且可能使用 FF 或 Chrome 来测试第二种情况,那么这可能就是原因。 jQuery.ajax 函数记录的跨域 JSON/JSONP 类型不会调用错误和全局回调。但是,我注意到它们仍然在 IE 中被调用,我认为这与使用 IE XMLHttpRequest 进行调用的 jQuery 有关。

似乎有人慷慨地创建了一个插件来处理此处提供的 JSONP 请求错误:http://code.google.com/p/jquery-jsonp/

【讨论】:

    【解决方案3】:

    应该是这样的格式:

    $.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 请求。
    • 查看 jquery website "注意:跨域脚本和跨域 JSONP 请求不调用此处理程序。"
    【解决方案4】:
    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');
    }
    

    【讨论】:

      猜你喜欢
      • 2013-04-08
      • 1970-01-01
      • 1970-01-01
      • 2014-10-08
      • 1970-01-01
      • 2012-09-08
      • 2012-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多