【问题标题】:Can a PHP script trick the browser into thinking the HTTP request is over?PHP 脚本能否欺骗浏览器认为 HTTP 请求已经结束?
【发布时间】:2010-11-29 00:35:40
【问题描述】:

我首先将我的脚本配置为即使在 HTTP 请求结束后也能运行

 ignore_user_abort(true);

然后清除一些文本。

 echo "Thats all folks!";
 flush();

现在我怎样才能让浏览器认为 HTTP 请求结束了?这样我就可以继续做自己的工作,而无需浏览器显示“页面加载”。

 header(??) // something like this?

【问题讨论】:

    标签: php http scripting httpwebrequest webserver


    【解决方案1】:

    标题不起作用(它们是标题,所以它们首先出现

    我不知道有什么方法可以在不终止脚本的情况下关闭 http 连接,尽管我认为有一些晦涩的方法。

    在请求完成后告诉我们您想做什么有助于我们提供更好的建议。

    但一般来说,我会考虑以下其中一项:

    1) 执行一些简单的命令行脚本(使用 exec()),如下所示:

    #!/bin/sh
    php myscript.php <arg1> <arg2> .. <argN> &
    

    然后从您的 http 绑定脚本开始,例如:

    <?PHP
    exec('/path/to/my/script.sh');
    ?>
    

    或者:

    2) 编写另一个程序(可能是一个持续运行的守护进程,或者只是一些经常被 cronned 执行的脚本),并弄清楚您的请求代码如何传递指令。您可以有一个排队工作的数据库表,或者尝试使其与某种平面文件一起工作。您还可以让您的基于 Web 的脚本调用一些命令行命令,从而使您的请求外脚本将一些工作排​​队。

    在一天结束时,您不希望您的脚本在 http 请求之后继续执行。假设您使用的是 mod_php,这意味着您将占用一个 apache 进程,直到脚本终止。

    【讨论】:

    • +1 同意。在 Web 请求之后继续执行将是一个糟糕的设计选择,并且会在服务器上产生不必要的内存开销。
    • 大时代同意蒂姆。问题的全部意义在于您想为以后保存大量工作,而不是让用户等待。好吧,您只是在占用可能会阻止其他用户的 httpd 资源。让 httpd 处理 Web 客户端并将其他工作传递给另一个组件 - 守护进程(+1 实时)、计划作业(+1 用于批处理和排队处理,可以真正等待),或其他任何东西。
    【解决方案2】:

    理论上,如果启用了 HTTP 1.1 keep-alive 并且客户端从服务器接收到它期望的字符数量,它应该将其视为响应的结束并继续渲染页面(同时保持连接仍然打开。)尝试发送这些标头(如果您无法通过其他方式启用它们):

    连接:保持活动 内容长度:n

    n 是您在响应正文中发送的字符数(输出缓冲可以帮助您计算。)很抱歉,我没有时间亲自测试。我只是提出建议以防万一。

    【讨论】:

    • 还是个坏主意,好像post-request处理需要超过几毫秒(这种情况下为什么要急着结束连接),你最好释放web服务器进程到处理新请求,并让一些后端进程(不绑定到 httpd)接管。
    • 我同意这可能是个坏主意。这只是为了满足 OP 的要求。
    【解决方案3】:

    也许 php.net 手册页上的这个特别评论会有所帮助:http://www.php.net/manual/en/features.connection-handling.php#71172

    【讨论】:

      【解决方案4】:

      实现此目的的最佳方法是使用输出缓冲。 PHP 在准备好并准备好时发送标头,但如果您使用 ob_* 将输出包装到浏览器,您可以在每一步中控制标头。

      如果你愿意,你可以在缓冲区中保存一个渲染的页面并发送标题,直到太阳在中国升起。这种做法就是为什么您可能会看到很多打开的&lt;?php 标签,但现在没有关闭标签。它可以防止脚本过早发送任何标头,因为可能需要考虑一些包含。

      【讨论】:

        【解决方案5】:

        这里是如何做到这一点。您告诉浏览器读取输出的前 N ​​个字符,然后关闭连接,同时您的脚本继续运行直到完成。

        <?php
        ob_end_clean();
        header("Connection: close");
        ignore_user_abort(true); // optional
        ob_start();
        echo ('Text the user will see');
        $size = ob_get_length();
        header("Content-Length: $size");
        ob_end_flush();     // Will not work
        flush();            // Unless both are called !
        
        // At this point, the browser has closed connection to the web server
        
        // Do processing here
        echo('Text user will never see');
        ?>
        

        【讨论】:

        • +1 绝妙的解决方案!感谢所有国王的骑兵都想不通的智慧。
        • 米兰的 hack 真的很棒。但是我不得不想知道你在做什么需要在网络请求结束后(从客户端的角度)咀嚼一个网络服务器进程。我当然希望这种可憎的东西不会扩大!
        • 与两天前发布的 Lukman 的答案中链接的 php 手册页中的代码相同(与字母相同)。
        • 如果 IE 使用带脚本标签的跨站点 ajax,并且响应缓慢 IE '垃圾邮件'请求。这迫使 IE 停止自毁并让服务器做它的事情。缓慢来自等待第三方响应。我让客户在超时时提出请求。如果缓存为空,则立即关闭连接。非常感谢!
        • @timdev,你提出了一些好的观点,但米兰的回答是关于头球和缓冲的很好的入门书,所以荣誉米兰。我正在开发一个使用大量 Ajax 调用的应用程序和一个绕过 session_start() 以防止在页面末尾可能需要 0.15 秒的会话锁定的进程。好吧,为什么不节省 0.15 秒并尽快关闭连接。
        猜你喜欢
        • 2011-03-05
        • 2010-11-28
        • 2018-08-27
        • 1970-01-01
        • 2010-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多