问题在于,无论客户端浏览器当前是否连接,PHP 脚本都会在很长一段时间内继续执行。如果客户端终止了对脚本的 Ajax 调用,那么脚本是否也会在服务器上终止?
4 回答
正如@metadings 所指出的,php 确实有一个名为connection_aborted() 的函数来检查连接中止。如果连接终止,它将返回 1,否则返回 0。
在较长的服务器端进程中,用户可能需要知道客户端是否与服务器断开连接,或者他是否关闭了浏览器,然后服务器可以安全地关闭该进程。
尤其是在应用程序使用 php 会话的情况下,如果我们在客户端断开连接后让长进程继续运行,那么服务器将对此会话无响应。来自同一客户端的任何其他请求都将等到前面的进程完全执行。出现这种情况的原因是进程运行时会话文件被锁定。但是,您可以有意地调用 session_write_close() 方法来解锁它。但这并非在所有情况下都可行,可能需要在进程结束时向会话写入一些内容。
现在,如果我们只在循环中调用 connection_aborted() ,那么无论连接是否关闭,它都将始终返回 0。
0 表示连接没有中止。这是误导。但是,经过重新搜索和实验,如果发现是php中的输出缓冲区是这个原因。
首先,为了检查中止,循环中的开发人员必须通过回显一些文本向客户端发送一些输出。例如:
print " ";
由于进程仍在运行,因此不会将输出发送到客户端。现在要发送输出,我们需要刷新输出缓冲区。
flush ();
ob_flush ();
然后,如果我们检查中止,那么它将给出正确的结果。
if (connection_aborted () != 0) {
die();
}
以下是工作示例,即使您使用的是 PHP 会话,它也可以工作:
session_start ();
ignore_user_abort ( TRUE );
file_put_contents ( "con-status.txt", "Process started..\n\n" );
for($i = 1; $i <= 15; $i ++) {
print " ";
file_put_contents ( "con-status.txt", "Running process unit $i \n", FILE_APPEND );
sleep ( 1 );
// Send output to client
flush ();
ob_flush ();
// Check for connection abort
if (connection_aborted () != 0) {
file_put_contents ( "con-status.txt", "\nUser terminated the process", FILE_APPEND );
die ();
}
}
file_put_contents ( "con-status.txt", "\nAll units completed.", FILE_APPEND );
编辑 2017 年 4 月 7 日
如果有人在 Windows 上使用 Fast-Cgi,那么当连接中止时,他实际上可以使用以下代码从内存中终止 CGI 线程:
if (connection_aborted () != 0) {
apache_child_terminate();
exit;
}
查看 PHPconnection_aborted()
函数。在进行处理时,您有时可以检查中止的连接以优雅地取消进度,就像在交互式线程模型中所做的那样。
我发现处理此超时问题的最简单方法之一是:
1:在服务器上设置一个值作为“处理”。启动一个独立的线程来做处理。
2:初始 ajax 调用返回成功
3:页面上的 javascript 进入“等待模式”,每 10 或 30 或 60 秒或 5 或 10 分钟或其他任何时间(取决于您的情况)发送一个新的 ajax 请求以查找输出服务器上的值是否仍设置为“处理”。
4:独立线程完成。它将服务器上的值设置为“完成”。
5:页面上的 javascript 进行下一个等待模式查询,并返回“完成”和相应的数据。
4b:如果长时间没有“完成”,则记录为失败。多少时间是淫秽的取决于你的情况。发送一个 ajax 调用,将值从“处理”更新为“取消”。5b:独立线程定期检查状态以确保它仍设置为“处理”。如果它看到模式转换为“取消”,它会自行取消。
这就是您要查找的内容:http: //php.net/manual/en/function.ignore-user-abort.php
在执行过程中停止脚本可能会导致意外结果,因此请注意购买者