某些操作需要花费太多时间,导致ajax请求超时。
如何先完成对请求的响应,然后继续执行该操作?
答案 0 :(得分:16)
ignore_user_abort
指令和ignore_user_abort
函数可能正是您要寻找的:它应该允许您将响应发送到浏览器,之后,仍然在您的服务器上运行一些计算
关于它的这篇文章可能会让您感兴趣:如何使用ignore_user_abort()进行带外处理;引用:
编辑2010-03-22:删除了链接(指向http:// ! waynepan.com/2007/10/11/ ! how-to-use-ignore_user_abort-to-do-process-out-of-band/
- 如果要尝试,请删除空格和!
,看到@Joel的评论。
基本上,当你使用时 你的php中
ignore_user_abort(true)
脚本,脚本将继续 即使用户按下了也能运行 esc或停在他的浏览器上。你怎么 用这个?
一种用途是 将内容返回给用户并允许 要关闭的连接 处理不需要的东西 用户互动。以下示例发送出去 对用户
$response
,关闭 连接(制作浏览器的 旋转器/加载杆停止),然后 执行do_function_that_takes_five_mins();
以下给出的例子:
ignore_user_abort(true);
header("Connection: close");
header("Content-Length: " . mb_strlen($response));
echo $response;
flush();
do_function_that_takes_five_mins();
(还有更多我没有复制粘贴)
请注意,您的PHP脚本仍然必须符合max_execution_time
和memory_limit
限制 - 这意味着您不应将此操作用于太多时间的操作。
这也将使用一个Apache进程 - 这意味着您不应该有几十个页面同时执行此操作。
我认为,仍然是增强使用体验的好方法; - )
答案 1 :(得分:2)
生成后台进程并返回后台进程ID,以便用户稍后可以通过某个秘密URL进行检查。
答案 2 :(得分:2)
排序取决于您要完成的任务。
就我而言,我需要做一堆服务器端处理,只需要将少量数据发送回浏览器 - 实际上是摘要信息。
我正在尝试创建一个邮件发件人 - 向超过250人发送电子邮件,但可能还有更多(取决于已向系统注册了多少人)。
PHP邮件处理程序很快,但对于大数字,不够快,所以它必然会超时。为了解决这个问题,我需要延迟服务器/ PHP端的超时,并保持浏览器挂起,直到所有数据都被汇总和显示。
我的解决方案 - 预告片。
基本上,我向用户发送了一条消息,说明了一些初始统计信息(尝试发送这么多电子邮件),创建了2个DIV框(一个用于当前状态信息,第二个用于最终摘要信息),显示页面页脚,启动了处理,完成后,更新摘要信息。它如下:首先收集您要处理的数据,然后获取一些摘要信息。在我的情况下,我提取了电子邮件地址列表,验证了它们并计算了它们。
然后显示“尝试”信息:
echo "Message contents:";
echo "<blockquote>$msgsubject<p>$msgbody</blockquote><p> </p>";
echo "Attempting <strong>" . $num_rows . "</strong> email addresses.";
现在为状态/最终信息创建一些DIV:
<div id=content name=content>
<div id=progress name=progress style='border: black 1px solid; width: ".$boxwidth."px; height: 20px;'></div>
<br>
</div>
其中$ boxwidth是您希望进度条的宽度(稍后解释)
请注意,它们基本上是空的 - 我们稍后会填充它们。
最后,通过显示页面的页脚来填写页面的其余部分(在我的情况下,我只是“包含”了相应的文件)。
现在,所有这些仍然在页面缓冲区中停留,无论是在服务器上(如果PHP正在缓冲)还是浏览器(因为它还没有被告知我们已经完成),所以让它得到它使用上面的“忽略”和“刷新”推送和/或显示:
ignore_user_abort(true);
flush();
现在浏览器开始显示内容了,我们需要给用户一些东西看,所以这就是挑逗 - 我们将创建一个状态栏,我们将在内部DIV中显示,以及最后一条消息外部DIV。
因此,当您循环浏览数据时,我会定期(我会留下“多久”由您决定),输出以下内容:
set_time_limit (3);
...
(process your data here)
...
<script>document.getElementById('progress').innerHTML += "<img src='images/progress_red.gif' width: $width height=20 border=0>"</script>
flush();
这将基本上将小的4x20 progress_red图像叠加在一起,使得看起来红色条在屏幕上移动。在我的情况下,我这样做了100次,基于我当前处理的数量的百分比来处理的总数。 “set_time_limit”将为现有限制添加3秒,这样您就知道您的脚本不会进入PHP时间限制墙。根据需要调整应用程序的3秒钟。
即使页面在技术上“完整”,javascript代码也会更新DIV html,我们的进度条会“移动”。
完成所有操作后,我会报告实际处理的项目数量并将其添加到外部DIV html并且页面已完成:
<script>document.getElementById('content').innerHTML += "Message was sent to $sentcnt people."</script>
浏览器很高兴,因为它满足了它的所有资格(以语言结尾的方式结束),用户看到了一些直到最后发生的事情,以及服务器
如果我可以提供帮助,我倾向于不使用Javascript,但是在这种情况下,通过Javascript没有花哨的CSS内容,所以它非常简单易懂,并且很容易看到浏览器网站上发生了什么。它的运作非常顺利。
我并不认为这是完美的,但对于一个简单,低开销的解决方案,它适用于我,而无需创建cronjobs,额外的排队机制或辅助进程。
答案 3 :(得分:-1)
您需要flush()
调用才能立即将响应发送到浏览器。