我在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"
答案 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;
...
问题解决了...只是希望在花费数小时试图修复错误之前我发现了真正的问题!