是否取消PHP应用程序中挂起的AJAX请求?
在页面之间导航时,取消XHR请求时遇到问题。我有一个页面,有8个请求被解雇。我在点击当前页面外的链接时取消它们。页面在等待下一个文档加载时暂停。这些XHR请求在开发人员工具中显示为已取消,但新文档会暂停,好像在等待它们返回 在这里,您可以看到页面被暂停,即使所有其他请求都被取消。新页面是唯一挂起的请求 在这里你可以看到,一旦页面最终跳转,TTFB是52.52秒。如果我在单击之前等待呼叫返回,则跳转是即时的 这里是新页面加载后的标题,如果有帮助的话。。。 我使用以下弗兰肯斯坦代码来管理XHR请求。我有一个底部的cancelAll函数中止请求是否取消PHP应用程序中挂起的AJAX请求?,php,mysql,ajax,zend-framework2,xmlhttprequest,Php,Mysql,Ajax,Zend Framework2,Xmlhttprequest,在页面之间导航时,取消XHR请求时遇到问题。我有一个页面,有8个请求被解雇。我在点击当前页面外的链接时取消它们。页面在等待下一个文档加载时暂停。这些XHR请求在开发人员工具中显示为已取消,但新文档会暂停,好像在等待它们返回 在这里,您可以看到页面被暂停,即使所有其他请求都被取消。新页面是唯一挂起的请求 在这里你可以看到,一旦页面最终跳转,TTFB是52.52秒。如果我在单击之前等待呼叫返回,则跳转是即时的 这里是新页面加载后的标题,如果有帮助的话。。。 我使用以下弗兰肯斯坦代码来管理XHR
XHRManager = {
Requests: [],
pendingRequests: [],
addNextRequest: function (r) {
var timeout = 0;
if (trace.isDevelopment()) {
timeout = 350;
}
setTimeout(function () {
if (r.url == XHRManager.pendingRequests[0].url && r.start == XHRManager.pendingRequests[0].start) {
XHRManager.pendingRequests.splice(0, 1);
}
else {
$( XHRManager.pendingRequests).each(function (ii, dd) {
if (dd.url == r.url && dd.start == r.start) {
XHRManager.pendingRequests.splice(ii, 1);
}
});
}
XHRManager.startNextRequest();
if (trace.findLocalStorage()) {
XHRManager.showTrace = true;
trace.show();
}
}, timeout);
},
requests: [],
intervals: [],
requestsInt: 0,
firstRun: true,
delay: 500,
globalTimeout: 5000,
showTrace: false,
startNextRequest: function () {
$( XHRManager.pendingRequests).each(function (i, d) {
if (d.start) {
}
if (i == 0) {
if (trace.domWatcher.constructor == Function) {
trace.domWatcher(d.requestNumber);
}
trace.log("Request #" + d.requestNumber + " started");
d.requestType(d);
}
});
if ( XHRManager.pendingRequests.length == 0) {
if (trace.isDevelopment()) {
trace.show();
}
}
},
AddToPendingRequests: function (url, params, cb, type, errCB) {
var rI = XHRManager.requestsInt;
XHRManager.requestsInt++;
var req = {url: url, params: params, cb: cb, requestNumber: rI, requestType: type};
if (errCB) {
req.errCB = errCB;
}
XHRManager.pendingRequests.push(req);
// if(trace.findLocalStorage()){
// trace.show();
// }
if (rI == 0 || XHRManager.pendingRequests.length == 1) {
XHRManager.startNextRequest();
}
},
writeVals: function (url, params, data, start, cb, requestNumber) {
if ($("meta[content='development']").length > 0) {
try {
var response = {};
response.requestNumber = requestNumber;
if (data.sql != "" && data.sql != undefined) {
response.sql = data.sql;
}
if (data.debug) {
if (data.debug.sql != "" && data.debug.sql != undefined) {
response.sql = data.debug.sql;
}
}
if (data.data != "" && data.data != undefined) {
response.data = data.data;
}
else {
if (data != "" || data != undefined) {
response.data = data;
}
}
if (url != "" && url != undefined) {
response.url = url;
}
if (params != "" && params != undefined) {
response.params = params;
}
if (cb) {
response.cb = cb.toString();
}
else {
response.cb = "";
}
response.requestStats = {};
response.requestStats.start = start;
response.requestStats.end = Date();
response.requestStats.totalTime = ((new Date(response.requestStats.end)).getTime() - (new Date(start)).getTime()) / 1000 + " sec(s)";
XHRManager.Requests.push(response);
}
catch (e) {
trace.log(e);
}
}
},
_create: function (r) {
var xm = XHRManager;
var start = Date();
var req = $.get(r.url, r.params, r.cb)
.done(function (data) {
XHRManager.writeVals(r.url, r.params, data, start, r.cb, r.requestNumber);
if (trace.isDevelopment() && trace.isOn()) {
XHRManager.addNextRequest(r);
}
});
xm.requests.push(req);
},
_createAjax: function (r) {
var xm = XHRManager;
var start = Date();
if (r.type == "PUT" || r.type == "DELETE") {
var req = $.ajax({
type: r.type,
xhrFields: {
withCredentials: true
},
url: r.url,
data: r.params,
success: function (data) {
XHRManager.writeVals(r.url, r.params, r.data, r.start, r.cb, r.requestNumber);
r.cb(data);
if (trace.isDevelopment() && trace.isOn()) {
XHRManager.addNextRequest(r);
}
},
error: r.errCB
});
xm.requests.push(req);
}
else {
var req = $.ajax({
type: r.type,
xhrFields: {
withCredentials: true
},
dataType: 'json',
json: 'json',
url: r.url,
data: r.params,
success: function (data) {
XHRManager.writeVals(r.url, r.params, data, start, r.cb, r.requestNumber);
r.cb(data);
if (trace.isDevelopment() && trace.isOn()) {
XHRManager.addNextRequest(r);
}
},
error: r.errCB
});
xm.requests.push(req);
}
},
_createJSON: function (r) {
var start = Date();
var xm = XHRManager;
var req = $.getJSON(r.url, r.params, r.cb)
.done(function (data) {
XHRManager.writeVals(r.url, r.params, data, start, r.cb, r.requestNumber);
if (trace.isDevelopment() && trace.isOn()) {
XHRManager.addNextRequest(r);
}
});
xm.requests.push(req);
},
create: function (url, params, cb) {
if (trace.isDevelopment() && trace.isOn()) {
XHRManager.AddToPendingRequests(url, params, cb, XHRManager._create);
}
else {
var r = {};
r.url = url;
r.params = params;
r.cb = cb;
XHRManager._create(r);
}
},
createAjax: function (url, params, type, cb, errCB) {
if (trace.isDevelopment() && trace.isOn()) {
XHRManager.AddToPendingRequests(url, params, cb, XHRManager._createAjax, errCB);
}
else {
var r = {};
r.url = url;
r.params = params;
r.cb = cb;
r.type = type;
r.errCB = errCB;
XHRManager._createAjax(r);
}
},
createJSON: function (url, params, cb) {
if (trace.isDevelopment() && trace.isOn()) {
XHRManager.AddToPendingRequests(url, params, cb, XHRManager._createJSON);
}
else {
var r = {};
r.url = url;
r.params = params;
r.cb = cb;
XHRManager._createJSON(r);
}
},
remove: function (xhr) {
var xm = XHRManager;
var index = xm.requests.indexOf(xhr);
if (index > -1) {
xm.requests.splice(index, 1);
}
index = xm.intervals.indexOf(xhr.interval);
if (index > -1) {
xm.intervals.splice(index, 1);
}
},
cancelAll: function () {
var xm = XHRManager;
$(xm.requests).each(function () {
var t = this;
t.abort();
});
$(xm.intervals).each(function () {
var t = this;
clearInterval(t);
});
xm.requests = [];
xm.intervals = [];
}
};
该站点使用jQuery、PHP、Zend Framework 2和SQL、Apache。我遗漏了什么?是否将Ajax请求存储在变量上?。如果没有,这就是你需要做的,完全取消一个请求
var xhr=$.ajax({
类型:“POST”,
url:“anyScript.php”,
数据:“数据1=0和数据2=1”,
成功:功能(msg){
//成功函数
}
});
//在这里,您将中止请求
xhr.abort()
我假设您已经这样做了,但请检查所有日志文件(php和apache)
还可以尝试以下方法:
php.ini
upload_max_filesize = 256M
post_max_size = 256M
.htaccess
php_value upload_max_filesize 256M
php_value post_max_size 256M
另一件让我讨厌的事是这部分
$(xm.requests).each(function () {
var t = this;
t.abort();
});
$(xm.intervals).each(function () {
var t = this;
clearInterval(t);
});
尝试将参数传递给回调并通过它们中止。我见过这样的情况,将这个赋值给一个带$的变量。每个循环实际上指向一个不同的对象或全局窗口
$(xm.requests).each(function (index, value) {
value.abort();
});
$(xm.intervals).each(function (index, value) {
clearInterval(value);
});
可能因果链
服务器没有意识到XHR请求被取消,因此相应的PHP进程保持运行
这些PHP进程使用会话,并在会话终止之前阻止对该会话的并发访问
可能的解决方案
解决上述两点中的任何一点都会打破链条,并可能解决问题:
(a) 默认情况下为FALSE
,但您可以使用非标准设置。在php.ini
中,将此设置更改回FALSE
,或者调用处理这些可中断请求的脚本
缺点:脚本只是终止。任何正在进行的工作都会被删除,可能会使系统处于脏状态
(b) 默认情况下,在尝试向客户端发送信息之前,PHP不会检测到用户已中止连接。在长时间运行脚本的过程中,定期执行echo
操作
缺点:此虚拟数据可能会损坏脚本的正常输出。在这里,脚本也可能使系统处于脏状态
PHP会话作为文件存储在服务器上。在session\u start()
上,脚本以写入模式打开会话文件,有效地获得了对其的独占锁定。使用同一会话的后续请求将被挂起,直到释放锁为止。脚本终止时会发生这种情况,除非明确关闭会话。尽早打电话给我
缺点:当关闭时,会话将无法再写入(除非您这样做,但这有点不雅观)。此外,脚本仍在运行,可能会浪费资源
我绝对推荐最后一个选择 我将它们分配给一个变量,并对它们运行abort()。上面红色的行是已取消的请求,因此abort()似乎正在工作。经过进一步检查,这似乎是服务器端PHP的问题?但仍然不确定如何解决这个问题。ApacheImigh可能会将来自同一客户机的请求排队,并在处理新请求之前等待完成旧的请求。至少,您可以通过发布到包含php如何运行的php脚本来查找问题?php fpm、mod_php、SUPPP或[…]?ini_get('ignore_user_abort')的输出是什么代码>?服务器端脚本在做什么(例如,一个长而重的任务、一个单一但非常昂贵的数据库查询、一堆较小的任务或[…])?可能会有帮助。您是否在PHP中使用会话?我建议将会话移动到DB中,在这种情况下,这个问题将得到解决。我有一个类似的问题,我用这种方式解决了它(你的观点2)。您可以允许多个脚本写入会话数据并引入竞争条件,也可以在数据库行上设置适当的锁并重新开始。不过,数据库方法确实可以更轻松地在脚本的各个阶段锁定/解锁会话。