响应 PHP 中的 ajax 请求后如何继续处理?

Posted

技术标签:

【中文标题】响应 PHP 中的 ajax 请求后如何继续处理?【英文标题】:How to continue process after responding to ajax request in PHP? 【发布时间】:2010-12-01 15:52:48 【问题描述】:

有些操作耗时过长,导致ajax请求超时。

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

ignore_user_abort 指令和ignore_user_abort 函数可能正是您要寻找的:它应该允许您将响应发送到浏览器,然后仍然在您的服务器上运行一些计算。

这篇文章你可能会感兴趣:如何使用 ignore_user_abort() 进行带外处理;引用: EDIT 2010-03-22 : 删除了链接(指向http:// ! waynepan.com/2007/10/11/ ! how-to-use-ignore_user_abort-to-do-process-out-of-band/ -- 如果你想尝试,删除空格和!,在看到@Joel 的评论后。

基本上,当您使用 ignore_user_abort(true) 在你的 php 中 脚本,脚本将继续 即使用户按下 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 进程——这意味着您不应该有几十个页面同时执行此操作。

不过,我想还是提升使用体验的好技巧;-)

【讨论】:

它不起作用。你可以试试这个看看:ignore_user_abort(true); header('Content-Type:text/plain'); header("连接:关闭");回声“某事”;睡眠(20);出口();响应仍然需要 20 秒。 “如何使用 ignore_user_abort() 进行带外处理”的链接包含恶意软件(通过引用者查看时,很糟糕)。看来博主被黑了…… @Joel:感谢您的评论;我已经编辑了我的答案以删除链接;;我刚刚留下了 URL,没有超链接,并且带有警告 其实这行得通,只是别忘了先回显 255 个字符,否则 IE 不会关闭连接... 为此工作,并且不更改 max_execution_time 您可以简单地调用 set_time_limit(0) 每次循环迭代(例如)。它会将倒计时重置为您的内存限制,因此不会关闭您的进程。【参考方案3】:

您需要调用flush() 才能将响应立即发送到浏览器。

【讨论】:

【参考方案4】:

有点取决于你想要完成什么。

在我的例子中,我需要做一堆服务器端处理,只有最少量的数据被发送回浏览器——实际上是摘要信息。

我正在尝试创建一个消息发件人 - 向 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 东西,所以它非常简单明了,很容易看到正在发生的事情,而且浏览器网站的开销也很低.而且运行起来非常流畅。

我并不认为这是完美的,但对于一个简单、低开销的解决方案来说,它对我有用,而无需创建 cronjob、额外的排队机制或辅助进程。

【讨论】:

以上是关于响应 PHP 中的 ajax 请求后如何继续处理?的主要内容,如果未能解决你的问题,请参考以下文章

Ajax+PHP打造等待进度条效果

ajax同步请求与异步请求的区别

发送一个 AJAX 请求以处理数据并返回多个 PHP 响应以更新其进度

前端如何尽量正确地处理ajax的异常?

php后端对ajax请求的响应应该如何?

如何在 Flux 架构中处理 ajax 请求响应?