Jquery Ajax请求在页面加载时在Safari中无限重复

时间:2015-11-20 16:23:33

标签: javascript jquery ajax nginx catalyst

我在Safari中遇到了一个棘手的Jquery Ajax问题。我正在使用Ajax在我正在开发的应用程序的一部分上加载/刷新静态svg内容。我首次加载页面时进行初始Ajax调用,然后根据页面上的菜单点击更新地图,然后调用相同的函数。所有人的代码都在下面,但首先是对问题的描述。

所有这些在Firefox和Chrome中运行良好,但在Safari中,页面初始加载和仅重新加载页面,正在向服务器生成无限循环的请求。奇怪的是,如果我停止加载页面,从菜单中对地图的后续更新工作就可以了。似乎Ajax调用正在返回错误状态 - 第二个"警报"在下面的代码中被触发,但对话框是空的,因此没有关于问题可能是什么的其他信息。

下面包含nginx访问日志行以及所有适用的代码段。 /var/log/nginx/error.log中没有错误,即使我使用CATALYST_DEBUG = 1设置启动fcgi也是如此。

真的希望有人能在这里给我一些见解,因为我不知所措!

更新 - 我在使用Catalyst开发服务器进行测试时遇到了同样的问题,因此这不是nginx或fcgi的问题。更可能是JS的东西。我也尝试在这里禁用块中表示为注释的代码位,它们对行为没有影响,正如预期的那样。

1)用于提供SVG图像的共享功能 - 请注意,我只是从Catalyst获取静态内容的位置,并将实际内容提供给nginx ...

function loadSvgMap(mapId) {
    jQuery.ajax({
        url:      "[% c.uri_for('/maps/update_map/') %]" + mapId,
        success:  function(result) {
            if(result.isOk == false) {
                alert(result.message);
            } else {
                $("#som_map").load(result);
            }
        },
        error:    function(result, status, errorThrown) {
            alert(errorThrown);
        },
        async:    true,
        dataType: 'text'
    });
}

2)页面加载时的初始调用

$(document).ready(function(){
    var mapId = [% map_id %];
    loadSvgMap(mapId);

/* other stuff to set the url and browser history*/
})

3)基于菜单点击的后续更新

$(document).on("click",".map_select", function(e){
    loadSvgMap(this.name);

    /* other stuff to update browser history and location */ 
})

4)页面加载的催化剂处理程序:

sub map :Path :Local :Args(1) {
    my ( $self, $c , $map_id ) = @_;

    $c->stash(menus => [$c->model('DB::Menus')->build_menu($c->model('DB::Map'), $c->model('DB::MapsMenus'))]);
    $c->stash(map_id => $map_id);                             
    $c->stash(neuron => '');                                 
    $c->stash(template => 'maps/som_main.tt2');

    my %params = %{$c->request->params};
    if (exists($params{neuron})) {
        return $c->res->redirect( $c->uri_for('neuron', $map_id, $params{neuron}));
    }
}

5)地图更新的催化剂处理程序

sub update_map :Path :Local :Args(1) {
    my ( $self, $c, $map_id ) = @_;

    my $fields = $c->model('DB::Map')->find($map_id);
    my $map_file = $fields->get_column('map_file');                               
    my $returnUrl = $c->uri_for('/static/svg', $map_file);

    $c->res->content_type("text/plain");
    $c->res->body($returnUrl);
}

6)nginx访问日志行

10.0.2.2 - - [20/Nov/2015:16:07:35 +0000] "GET /maps/map/305 HTTP/1.1" 200 3335 "http://poppy.med.umich.edu:5000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/601.1.56 (KHTML, like Gecko) Version/9.0 Safari/601.1.56"
10.0.2.2 - - [20/Nov/2015:16:07:35 +0000] "GET /maps/get_map_info/305 HTTP/1.1" 499 0 "http://poppy.med.umich.edu:5000/maps/map/305" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/601.1.56 (KHTML, like Gecko) Version/9.0 Safari/601.1.56"
10.0.2.2 - - [20/Nov/2015:16:07:35 +0000] "GET /maps/update_map/305 HTTP/1.1" 200 51 "http://poppy.med.umich.edu:5000/maps/map/305" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/601.1.56 (KHTML, like Gecko) Version/9.0 Safari/601.1.56"

请注意" 499"一个请求的状态表示客户端挂起。这并不总是会影响同一个请求 - 似乎只是在Safari中触发错误时当前正在运行的任何一个请求。一旦初始"警报"被解雇(如果我检查"不要显示更多警报......"),这三行将无限重复,直到我停止页面加载。之后,我可以使用菜单选择地图,一切正常。

为了比较,这是来自firefox的请求的日志输出...

10.21.136.38 - - [20/Nov/2015:16:30:03 +0000] "GET /maps/map/1 HTTP/1.1" 200 3318 "http://10.21.136.66/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0"
10.21.136.38 - - [20/Nov/2015:16:30:04 +0000] "GET /maps/update_map/1 HTTP/1.1" 200 48 "http://10.21.136.66/maps/map/1" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0"
10.21.136.38 - - [20/Nov/2015:16:30:04 +0000] "GET /maps/get_map_info/1 HTTP/1.1" 200 394 "http://10.21.136.66/maps/map/1" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0"

1 个答案:

答案 0 :(得分:0)

经过几个小时的实验,我确定这个问题实际上与Jquery Ajax完全无关。相反,它与我对浏览器历史的操作有关。具体来说,我正在监听window.popstate事件以触发浏览器导航按钮的处理:

$(window).on('popstate', function(event) {
    var state = event.originalEvent.state;
    if (state) {
        window.location.assign(state.url);
    } else {
        window.location.assign(document.location.href);
    }
});

这就是问题,因为Safari会在浏览器历史记录发生变化时触发一个popstate事件,无论是来自导航操作还是页面(重新)加载。 (前段时间他们在Chrome中修复了一些东西 - 来吧,Safari!遵循标准很多?)为了解决这个问题,我应用了以下黑客:

1)为浏览器历史记录条目创建状态时,请包含一个标记以指示我们创建了该条目:

var state = { url: newUrl, title: newTitle, loadTag: true };
window.history.pushState(state, "", newUrl); // or replaceState, for first page load

2)在popstate监听器中,检查我们的标签,除非找到它,否则什么都不做:

$(window).on('popstate', function(event) {
    var state = event.originalEvent.state;
    if (!state.loadTag) return;

    ...

问题解决了...只是希望在花费数小时试图修复错误之前我发现了真正的问题!