Jquery Ajax 在页面加载时在 Safari 中无限重复请求
Jquery Ajax request repeating infinitely in Safari on page load
我在 Safari 中遇到 Jquery Ajax 的小问题。我在我正在开发的应用程序的一部分上使用 Ajax 到 load/refresh 静态 svg 内容。我在首次加载页面时进行初始 Ajax 调用,然后根据页面上的菜单点击,通过对同一功能的后续调用来更新地图。下面是所有代码,但首先是对问题的描述。
这一切在 Firefox 和 Chrome 中工作正常,但在 Safari 中,页面 仅在初始加载和页面重新加载时 正在生成无限循环对服务器的请求。奇怪的是,如果我停止页面加载,随后从菜单更新地图就可以正常工作。 Ajax 调用似乎正在返回错误状态——下面代码中的第二个 "alert" 正在被触发,但对话框是空的,因此没有关于问题可能是什么的其他信息。
nginx 访问日志行以及所有适用的代码片段包含在下面。 /var/log/nginx/error.log 中没有错误,即使我使用 CATALYST_DEBUG=1 设置启动 fcgi。
真的很希望有人能给我一些见解,因为我不知所措!
UPDATE -- 我 运行 在测试 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) 用于页面加载的 Catalyst 处理程序:
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 中触发错误时当前 运行 中的那个。一旦最初的 "alert" 被取消(如果我选中 "Don't show more alerts..."),这三行将无限重复,直到我停止页面加载。之后,我可以使用菜单选择地图,一切正常。
为了比较,这里是来自 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"
经过几个小时的实验,我确定这个问题实际上与 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!遵循标准?)为了解决这个问题,我应用了以下 hack:
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;
...
问题已解决...真希望我能在花费数小时尝试修复错误问题之前发现真正的问题!
我在 Safari 中遇到 Jquery Ajax 的小问题。我在我正在开发的应用程序的一部分上使用 Ajax 到 load/refresh 静态 svg 内容。我在首次加载页面时进行初始 Ajax 调用,然后根据页面上的菜单点击,通过对同一功能的后续调用来更新地图。下面是所有代码,但首先是对问题的描述。
这一切在 Firefox 和 Chrome 中工作正常,但在 Safari 中,页面 仅在初始加载和页面重新加载时 正在生成无限循环对服务器的请求。奇怪的是,如果我停止页面加载,随后从菜单更新地图就可以正常工作。 Ajax 调用似乎正在返回错误状态——下面代码中的第二个 "alert" 正在被触发,但对话框是空的,因此没有关于问题可能是什么的其他信息。
nginx 访问日志行以及所有适用的代码片段包含在下面。 /var/log/nginx/error.log 中没有错误,即使我使用 CATALYST_DEBUG=1 设置启动 fcgi。
真的很希望有人能给我一些见解,因为我不知所措!
UPDATE -- 我 运行 在测试 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) 用于页面加载的 Catalyst 处理程序:
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 中触发错误时当前 运行 中的那个。一旦最初的 "alert" 被取消(如果我选中 "Don't show more alerts..."),这三行将无限重复,直到我停止页面加载。之后,我可以使用菜单选择地图,一切正常。
为了比较,这里是来自 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"
经过几个小时的实验,我确定这个问题实际上与 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!遵循标准?)为了解决这个问题,我应用了以下 hack:
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;
...
问题已解决...真希望我能在花费数小时尝试修复错误问题之前发现真正的问题!