我的目标是在Ajax中创建一个函数,以将帖子数据发送到其他服务器上的PHP脚本。预期的结果是使PHP脚本与客户端断开连接,并在服务器上的后台运行整个PHP脚本,以允许用户自由浏览,而不必等待PHP脚本完成。我已成功将数据发布到PHP脚本,但是从客户端断开连接后,我无法使PHP脚本继续运行。我不希望或不需要PHP脚本将任何内容输出到任何其他脚本。我只需要它在后台运行。
我已经尝试在PHP中使用ignore_user_abort(true)
,header("Connection: close\r\n")
和其他连接处理,但是没有成功。这是我实现所需功能的最新尝试。
发送脚本
<script>
function sendingRequest()
{
var form = document.getElementById("submit_change");
var var1 = document.getElementById('var1').value;
var var2 = document.getElementById('var2').value;
var var3 = document.getElementById('var3').value;
var dataString = 'var1='+ var1 + '&var2=' + var2 + '&var3=' + var3;
$.ajax({
type:"post",
url:"recievingScript.php",
data:dataString,
cache:false
});
form.submit();
return false;
}
</script>
PHP脚本
<?php
ignore_user_abort(true);
//includes, uses, requires, establish db connection
$var1 = $_POST['var1'];
$var2 = $_POST['var2'];
$var3 = $_POST['var3'];
header("Access-Control-Allow-Origin: *");
header("Connection: close");
//Code to be run
//end script
?>
成功:在Ajax帖子中,PHP脚本成功运行,并将成功消息发送到名为PHP脚本的脚本。但是脚本运行大约需要10秒钟,因此让用户等待脚本完成不是一个好主意。任何建议表示赞赏,谢谢!
答案 0 :(得分:1)
您可以设置所谓的后台工作人员。执行的功能将在“后台”完成,这意味着用户不必等到功能完全完成。然后,您可以公开路由/ Api来调用该函数。 在laravel中,他们将其称为可以排队的作业。
就个人而言,除了在Laravel中开箱即用之外,我没有设置后台工作人员的任何经验。但是您可以检查这些参考!
答案 1 :(得分:0)
我很好奇,决定尝试从我的评论中提出xhr.abort()
的建议。
下面仅是完成长时间运行的PHP AJAX请求的基本示例,而无需客户端等待服务器的响应,也不必提前终止XHR和PHP继续执行脚本。
此方法可以调整为运行本地脚本,该脚本也向外部主机发出cURL或SOAP请求。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Send It</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<form method="post" action="https://second.domain.com/recievingScript.php">
<p><input type="text" name="name"/></p>
<p>
<button type="submit">Send</button>
</p>
</form>
<script type="text/javascript">
const writeLog = function(msg) {
let date = new Date();
window.console.log(date.toISOString() + ' ' + msg);
};
jQuery(function($) {
let f = $('form');
let xhrOptions = {
url: f.attr('action'),
type: f.attr('method'),
data: {},
cache: false,
xhr: function() {
let xhr = $.ajaxSettings.xhr();
if ('undefined' === typeof xhr.upload.onload || null === xhr.upload.onload) {
//override the upload.onload event, only if it has not already been
xhr.upload.onload = function() {
//onload is triggered immediately after the POST headers are sent to the recipient
writeLog('Upload Completed - Ending Request');
xhr.abort();
};
}
return xhr;
},
};
f.on('submit', function(e) {
e.preventDefault();
let formData = f.serialize();
writeLog(formData);
$.ajax($.extend(true, xhrOptions, {
data: formData
})).done(function(responseText) {
//this is never triggered since the request is aborted
writeLog('Success');
writeLog(responseText);
}).fail(function(jqxhr) {
writeLog('Request ' + (jqxhr.readyState !== 4 ? 'Aborted' : 'Failed'));
});
return false;
});
});
</script>
</body>
</html>
回复:
send.html:18 2019-01-15T21:19:11.445Z name=Hello%20Dagroa
send.html:18 2019-01-15T21:19:11.558Z Upload Completed - Ending Request
send.html:18 2019-01-15T21:19:11.558Z Request Aborted
\date_default_timezone_set('UTC');
\ignore_user_abort(true);
\header('Access-Control-Allow-Origin: https://first.domain.com');
if (!empty($_POST)) {
$dateStart = new \DateTimeImmutable();
//create a placeholder file
if ($file = \tempnam(__DIR__, 'tmp_')) {
$i = 1;
//PHP >= 7 required for random_int - PHP < 7 use mt_rand() instead
$rand = \random_int(5, 30);
//add the number of seconds to create a stop date
$dateStop = $dateStart->add(new \DateInterval(\sprintf('PT' . $rand . 'S')));
while (new \DateTime() < $dateStop) {
//loop until the stop date is reached
$i++;
}
$dateEnd = new \DateTime();
$dateDiff = $dateEnd->diff($dateStart);
//write result to the temporary file
\file_put_contents($file, \json_encode([
'file' => \basename($file),
'scriptFile' => \basename($_SERVER['SCRIPT_FILENAME']),
'iterations' => $i,
'start' => $dateStart->format(\DATE_RFC3339_EXTENDED),
'end' => $dateEnd->format(\DATE_RFC3339_EXTENDED),
'stop' => $dateStop->format(\DATE_RFC3339_EXTENDED),
'elapsed' => $dateDiff->format('%i minutes, %s seconds, %f microseconds'),
'slept' => $rand,
'post' => $_POST,
], \JSON_PRETTY_PRINT));
}
}
回复:
{
"file": "tmp_hjLk4y",
"scriptFile": "recievingScript.php",
"iterations": 9653192,
"start": "2019-01-15T21:19:12.171+00:00",
"end": "2019-01-15T21:19:36.171+00:00",
"stop": "2019-01-15T21:19:36.171+00:00",
"elapsed": "0 minutes, 24 seconds, 3 microseconds",
"slept": 24,
"post": {
"name": "Hello Dagroa"
}
}
注意:我使用php-fpm 7.2作为使用Apache 2.4的fcgi代理, 除了
random_int
函数调用和DATE_RFC3339_EXTENDED
以外,其他都没有关系。另外
const
和let
JavaScript中的用法是ECMAScript 6规范,当前所有主流浏览器版本均支持该规范。应该禁用PHP输出缓冲,否则,您可能需要使用
flush()
和/或ob_end_flush()
强制将其刷新。 Web服务器配置中的某些其他条件也会影响输出缓冲,例如gzip
编码。jQuery将在
OPTIONS
请求方法之前发出一个POST
请求方法。确保检查$_POST
不为空,或检查$_SERVER['REQUEST_METHOD']
是否为所需的类型,以防止重复执行。