Yes.
如果正确利用 HTTP 标头,这可以轻松完成,无需任何异步处理。
正常情况下,一旦另一端的客户端关闭连接,PHP 就会停止处理。如果您想在此事件之后继续处理,您需要做一件事:告诉 PHP 忽略用户中止。如何?
ignore_user_abort()
这将使您的脚本即使在客户端无法躲避之后也能继续运行。但我们还面临着如何告诉客户端他们发出的请求已完成以便其关闭连接的问题。通常,如果我们不指定这些标头,PHP 会透明地为我们处理发送这些标头。不过,在这里,我们需要明确地执行此操作,否则客户端将不知道我们何时希望他们停止阅读响应。
为此,我们必须发送适当的 HTTP 标头来告诉客户端何时关闭:
Connection: close
Content-Length: 42
这种标头组合告诉客户端,一旦读取了 42 字节的实体主体响应,消息就已完成,并且应该关闭连接。这种方法有几个后果:
- 您必须生成您的回复BEFORE发送任何输出,因为您必须确定其内容长度大小(以字节为单位),以便可以发送正确的标头。
- 您必须实际发送这些标头BEFORE您回显任何输出。
所以你的脚本可能看起来像这样:
<?php
ignore_user_abort();
// do work to determine the response you want to send ($responseBody)
$contentLength = strlen($responseBody);
header('Connection: close');
header("Content-Length: $contentLength");
flush();
echo $responseBody;
// --- client will now disconnect and you can continue processing here ---
The big "Gotchya" with this method is that when you're running PHP in a web SAPI you can easily run up against the max time limit directive if you do time-consuming processing after the end user client closes the connection. If this is a problem, you may need to consider an asynchronous processing option using cron because there is no time limit when PHP runs in a CLI environment. Alternatively, you could just up the time limit of your scripts in the web environment using set_time_limitdocs http://php.net/manual/en/function.set-time-limit.php.
It's worth mentioning that if you do something like this, you may also want to add a check to connection_aborted()docs https://www.php.net/manual/en/function.connection-aborted.php while generating your response body so that you can avoid the additional processing if the user aborts before completing the transfer.