通过Ajax发送帖子以在后台运行PHP脚本

时间:2019-01-15 04:33:28

标签: php ajax xmlhttprequest

我的目标是在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秒钟,因此让用户等待脚本完成不是一个好主意。任何建议表示赞赏,谢谢!

2 个答案:

答案 0 :(得分:1)

您可以设置所谓的后台工作人员。执行的功能将在“后台”完成,这意味着用户不必等到功能完全完成。然后,您可以公开路由/ Api来调用该函数。 在laravel中,他们将其称为可以排队的作业。

就个人而言,除了在Laravel中开箱即用之外,我没有设置后台工作人员的任何经验。但是您可以检查这些参考!

Class Worker PHP

doBackground PHP

Laravel Queues

答案 1 :(得分:0)

我很好奇,决定尝试从我的评论中提出xhr.abort()的建议。

下面仅是完成长时间运行的PHP AJAX请求的基本示例,而无需客户端等待服务器的响应,也不必提前终止XHR和PHP继续执行脚本。

此方法可以调整为运行本地脚本,该脚本也向外部主机发出cURL或SOAP请求。

https://first.domain.com/send.html

<!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

https://second.domain.com/recievingScript.php

\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以外,其他都没有关系。

     

另外   constlet   JavaScript中的用法是ECMAScript 6规范,当前所有主流浏览器版本均支持该规范。

     

应该禁用PHP输出缓冲,否则,您可能需要使用flush()和/或ob_end_flush()强制将其刷新。 Web服务器配置中的某些其他条件也会影响输出缓冲,例如gzip编码。

     

jQuery将在OPTIONS请求方法之前发出一个POST请求方法。确保检查$_POST不为空,或检查$_SERVER['REQUEST_METHOD']是否为所需的类型,以防止重复执行。