我想知道是否可以立即发送 HTTP 响应并继续执行脚本。
背景:在我向服务器提出的所有请求中,有一个创建了 Excel 文件(使用 PHPSpreadSheet),因为创建此文件可能需要更长的时间,我正在考虑向客户端响应HTTP 202 状态代码,例如:
header("HTTP/1.1 202 Excel file in process");
并在每次状态代码到达时在主 js 文件上编写一个侦听器,以激活时间间隔 ( setInterval()) 并每隔一定秒数询问 Excel 文件是否准备就绪
$(document).ajaxSuccess(function ( event, xhr, settings) {
if(xhr.status === 202) {
//Activate the setInterval function to ask the server every 10 seconds whether the file is ready or not
}
});
Run Code Online (Sandbox Code Playgroud)
(我知道我必须激活/停用间隔)
因此,每当我收到有关 createExcel.php 文件的请愿书时,我想立即回复用户已收到请愿书并开始制作此类 Excel 文件
就像是:
<?php
//Tell user that the petition has being received
header("HTTP/1.1 202 Excel file in process");
//Kill this process or close this connection but continue executing
//Call createExcel.php
Run Code Online (Sandbox Code Playgroud)
createExcel.php 文件将更新数据库中的某些表,确认文件已创建,间隔请求将每 10 秒查询一次相同的表
这就是我正在尝试做的,我只是想让你们告诉我如何调用另一个文件,而无需等待被调用的文件完成响应用户。
我正在考虑使用exec()但我从未使用过它(我在发布后立即对其进行测试),最重要的是任何经验或提示将不胜感激(例如优化提示等)
我在 Stack Overflow 上看到了这个问题,但答案建议创建一个 cron 服务,这对我来说不是解决方案。
谢谢!
编辑 - -
嘿,万一有人看到这个,我找到了我的问题的两个解决方案:我尝试过的第一个但给权限带来了很多麻烦的是:https : //code-boxx.com/php-background-process/
但是如果你从 cmd 运行它,这个会很好地工作,但是当你认为浏览器运行它时,Apache 禁止你使用执行命令;因此exec(),popen()除非您更改文件夹中的权限,否则类似的命令将不起作用,我认为这是一个安全问题,所以我发现了这个非常漂亮的功能fastcgi_finish_request()
编辑 2 - 解决方案 https://qastack.mx/programming/15273570/continue-processing-php-after-sending-http-response 这有效我们刷新缓冲区中的所有内容并关闭连接,然后我们继续执行脚本。
在JS中:
\n$(document).ajaxSuccess(function ( event, xhr, settings) {\n if(xhr.status === 202) {\n //console.log("Your file is in process");\n //console.log(xhr.responseJSON); \n //Activate interval to check if file is ready \n }\n});\n//Make petition\n$.post("petitionsHandler.php", {"texto":"Hello world, greeting from M\xc3\xa9xico!"}, function (resp){\n //Handle responses\n}, "json").fail(function () {\n //Handle errors\n});\n\nRun Code Online (Sandbox Code Playgroud)\n在 PHP 中
\n<?php\n$text = $_POST["text"];\n //If you are using sessions don\'t forget to close the session file\n //Or such will be blocked until long script finishes\n session_write_close();\n header("HTTP/1.1 202 Solicitud recibida"); #This is the code I wanted to send\n header("Content-Type: application/json"); #Depends the kind of data you\'re sending to the client\n // Buffer all upcoming output...\n ob_start();\n\n // Send your response.\n echo \'{"success":true, "message":"Your request has been received."}\';\n // Get the size of the output.\n $size = ob_get_length();\n\n // Disable compression (in case content length is compressed).\n //header("Content-Encoding: none"); #I didn\'t need this but check your situation\n\n // Set the content length of the response.\n header("Content-Length: {$size}");\n\n // Close the connection.\n header("Connection: close");\n\n // Flush all output.\n ob_end_flush();\n ob_flush();\n flush();\n //All outputs have now been sent to the client\n //You can continue executing your long tasks \n \n include_once(\'createExcel.php\');\nRun Code Online (Sandbox Code Playgroud)\n创建Excel.php
\n<?php\nsleep(10); #You can use to checkthat the code works\n//The above code will respond the client immediately and after ten seconds the Excel file will be created\nrequire "PHPSpreadSheet/vendor/autoload.php";\nuse PhpOffice\\PhpSpreadsheet\\Spreadsheet;\nuse PhpOffice\\PhpSpreadsheet\\Writer\\Xlsx;\n$spreadsheet = new Spreadsheet();\n$sheet = $spreadsheet->getActiveSheet();\n$sheet->setCellValue(\'A1\', $text);\n$writer = new Xlsx($spreadsheet);\n$writer->save(\'MyFile.xlsx\');\nRun Code Online (Sandbox Code Playgroud)\n当然,您必须进行验证,因此您不会在后台运行大量进程,但我希望此示例已显示总体思路。
\n这并不完全是我使用的代码,但这就是在响应客户端后继续执行代码所需的全部内容。
\n在我看来,我认为这比使用exec()或调用命令终端的类似函数更好,因为这可能是一个潜在的漏洞,因此您不必更改权限或任何内容。
注意:如果您正在使用会话,请记住使用,session_write_close()因为繁重的任务会阻塞文件,直到此类任务完成。
我希望它有帮助:)
\n我的答案基于此博客:https://qastack.mx/programming/15273570/continue-processing-php-after-sending-http-response
\n