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

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

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

【问题讨论】:

    标签: php ajax timeout


    【解决方案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、额外的排队机制或辅助进程。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-04-14
          • 2018-02-22
          • 2015-12-02
          • 1970-01-01
          • 2020-12-20
          • 2015-04-26
          • 1970-01-01
          • 2019-09-01
          相关资源
          最近更新 更多