如何在PHP中响应ajax请求后继续进程?

时间:2009-09-26 13:42:33

标签: php ajax timeout

某些操作需要花费太多时间,导致ajax请求超时。

如何先完成对请求的响应,然后继续执行该操作?

4 个答案:

答案 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_timememory_limit限制 - 这意味着您不应将此操作用于太多时间的操作。

这也将使用一个Apache进程 - 这意味着您不应该有几十个页面同时执行此操作。

我认为,仍然是增强使用体验的好方法; - )

答案 1 :(得分:2)

生成后台进程并返回后台进程ID,以便用户稍后可以通过某个秘密URL进行检查。

答案 2 :(得分:2)

排序取决于您要完成的任务。

就我而言,我需要做一堆服务器端处理,只需要将少量数据发送回浏览器 - 实际上是摘要信息。

我正在尝试创建一个邮件发件人 - 向超过250人发送电子邮件,但可能还有更多(取决于已向系统注册了多少人)。

PHP邮件处理程序很快,但对于大数字,不够快,所以它必然会超时。为了解决这个问题,我需要延迟服务器/ PHP端的超时,并保持浏览器挂起,直到所有数据都被汇总和显示。

我的解决方案 - 预告片。

基本上,我向用户发送了一条消息,说明了一些初始统计信息(尝试发送这么多电子邮件),创建了2个DIV框(一个用于当前状态信息,第二个用于最终摘要信息),显示页面页脚,启动了处理,完成后,更新摘要信息。它如下:

首先收集您要处理的数据,然后获取一些摘要信息。在我的情况下,我提取了电子邮件地址列表,验证了它们并计算了它们。

然后显示“尝试”信息:

echo "Message contents:";
echo "<blockquote>$msgsubject<p>$msgbody</blockquote><p>&nbsp;</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()调用才能立即将响应发送到浏览器。