php - PHP脚本输出的AJAX持续响应

标签 php jquery ajax nginx flush

我的 PHP 脚本的 AJAX 响应有问题...

我创建了“Status”div,我想在其中输出 PHP 脚本的响应。它工作得很好,但只有当整个脚本完成时才会显示响应,我想“实时”输出每个 echo ..

这是我的文件:

form.php

<!-- left column -->
<div class="col-md-6">
    <!-- general form elements -->
    <div class="card card-primary">
        <div class="card-header">
            <h3 class="card-title"><?php echo $xmlData->name ?></h3>
        </div>
        <!-- /.card-header -->
        <!-- form start -->
        <form id="upload_form" enctype="multipart/form-data" method="post">
            <div class="card-body">
                <div class="form-group">
                    <label for="debFile">Deb file</label>
                    <span id="debMSG"></span>
                    <div class="input-group">
                        <div class="custom-file">
                            <input name="debFile" type="file" class="custom-file-input" id="debFile">
                            <label class="custom-file-label" for="debFile">Choose .deb file</label>
                        </div>
                    </div>
                </div>
                <div class="form-group">
                    <label for="version">Version</label>
                    <input type="text" name="version" id="version" class="form-control" value="<?php echo ver_up($xmlData->changelogs->change->version); ?>">
                </div>
                <div class="form-group">
                    <label for="log">Log</label>
                    <input type="text" name="log" id="log" class="form-control" value="Bug fix">
                </div>
                <div class="form-check">
                    <input name="tweet" type="checkbox" class="form-check-input" id="tweet" value="1">
                    <label class="form-check-label" for="tweet">Auto-post on Twitter</label>
                </div>
            </div>
            <!-- /.card-body -->

            <div class="card-footer">
                <button id="submit" name="upload" type="submit" class="btn btn-primary">Update</button>
            </div>
        </form>
    </div>
    <!-- /.card -->
</div>
<!-- Status -->
<div id="status" class="col-md-6" style="display:none;">
    <div class="card card-default">
        <div class="card-header">
            <h3 class="card-title">Status:</h3>
        </div>
        <div class="alert alert-default">
            <ul id="output" class="list-group"></ul>
        </div>
    </div>
</div>
<!--/.col (right) -->

form.php 中的ajax

<script type="text/javascript">
$(document).ready(function () {
    bsCustomFileInput.init();

    const Toast = Swal.mixin({
        toast: true,
        position: 'top-end',
        showConfirmButton: false,
        timer: 5000
    });

    $(document).on('submit', '#upload_form', function(event){
        event.preventDefault();

        if($('#debFile').val() == '')
        {
            $('#debMSG').html('<div class="alert alert-danger">Enter .deb file!</div>');
            $('#debMSG').show();
            setTimeout(function() {
                $('#debMSG').fadeOut('fast');
            }, 5000);
            return false;
        }
        else
        {

            $.ajax({
                type: 'POST',
                url: 'scripts/test.php',
                data: new FormData(this),
                // async: true,
                cache: false,
                processData: false,
                contentType: false,
                beforeSend:function()
                {
                    $('#debMSG').hide();
                    $('#submit').attr('disabled', 'disabled');
                    // $('#status').fadeIn('slow');
                }
            })
            .done(function(data) {
                // console.log(data);
                $('#output').append(data);
                $('#status').fadeIn('slow');
                // if(!data.success){
                //  $('#submit').removeClass('btn-primary').addClass('btn-danger');
                //  $('#submit').attr('disabled', false);
                //  $('#submit').removeAttr('name type');
                //  $('#submit').attr('onClick', 'location.reload();');
                //  $('#submit').html('Reload');
                //  Toast.fire({
                //      icon: 'error',
                //      title: 'There was an error while updating tweak!'
                //  })
                // } else {
                    $('#submit').removeClass('btn-primary').addClass('btn-success');
                    $('#submit').attr('disabled', false);
                    $('#submit').removeAttr('name type');
                    $('#submit').attr('onClick', 'window.location.href = "manage-packages.php";');
                    $('#submit').html('Finish');
                    Toast.fire({
                        icon: 'success',
                        title: 'Tweak has been successfully updated!'
                    })
                // }
            })
            .fail(function(data) {
                console.log(data);
                $('#output').append("There was an error while updating tweak!");
                // $('#output').removeClass('alert-success').addClass('alert-danger');
                $('#status').fadeIn('slow');
                $('#submit').removeClass('btn-primary').addClass('btn-danger');
                $('#submit').attr('disabled', false);
                $('#submit').removeAttr('name type');
                $('#submit').attr('onClick', 'location.reload();');
                $('#submit').html('Reload');
                Toast.fire({
                    icon: 'error',
                    title: 'There was an error while updating tweak!'
                })
            });
        }
    });
});
</script>

test.php

<?php

header('Content-type: text/html; charset=utf-8');

require_once("../../src/config-ssh.php");
require_once("../../src/functions.php");

$deb_dir = "/var/www/html/debs/";
$repo_dir = "/var/www/html/";

function output($val) {
    echo nl2br ($val);
    flush();
    ob_flush();
    sleep(1);
}

try {
    if (isset($_FILES["debFile"]["name"])) {
        $debFile = $_FILES["debFile"]["tmp_name"];
        $deb_file = $deb_dir . basename($_FILES["debFile"]["name"]);

        if (!file_exists($deb_file)) {
            output("<li class=\"list-group-item list-group-item-success\">DEB file \"". basename( $_FILES["debFile"]["name"]). "\" has been uploaded.</li>");
        } else {
            throw new Exception("<li class=\"list-group-item list-group-item-danger\">DEB file \"". basename( $_FILES["debFile"]["name"]). "\" already exists!</li>");
        }
    } else {
        throw new Exception("<li class=\"list-group-item list-group-item-danger\">You didn't choose any DEB file!</li>");
    }

    preg_match('/(.*)_(.*)_(.*)\.deb/', basename($_FILES["debFile"]["name"]), $deb_reg);
    $dirname = $deb_reg[1];
    $prev_ver = ver_down($deb_reg[2]);
    $exten = $deb_reg[3] . ".deb";
    $prev_deb_name = $dirname."_".$prev_ver."_".$exten;
    $prev_deb = $deb_dir . $prev_deb_name;

    if (isset($_POST['version']) && isset($_POST['log'])) {
        output("<li class=\"list-group-item list-group-item-success\">Values were added to XML!</li>");
    }

    if (file_exists($prev_deb)) {
        output("<li class=\"list-group-item list-group-item-success\">Previous version of DEB file (\"". $prev_deb_name . "\") was deleted!</li>");
    } else {
        throw new Exception("<li class=\"list-group-item list-group-item-danger\">DEB file \"". $prev_deb_name . "\" wasn't deleted!</li>");
    }


    // Run a command
    output("<li class=\"list-group-item list-group-item-info\">Running Repo update script...</li>");
        output("<li class=\"list-group-item list-group-item-success\">Script finished successfully.</li>");

    // Auto-post Tweet
    if (isset($_POST['tweet'])) {
        output("$msg");
        output("<li class=\"list-group-item list-group-item-success\">Tweet has been successfully posted.</li>");
    }

    exit();
}

catch( Exception $e ) {
    $message = $e->getMessage();

    die( "ERROR: " . $message );
}

?>

最后,它打印以下状态输出: enter image description here

我已经尝试过几个教程,但没有一个能解决这个问题...

感谢您的建议!

最佳答案

您需要将处理程序绑定(bind)到 XmlHttpRequest 对象的 progress 事件。 jQuery 不提供执行此操作的 native 接口(interface),但如果您仍然想使用 jQuery 执行 AJAX 调用而不是直接使用 XmlHttpRequest 对象,则可以使用 xhr 更改底层 XmlHttpRequest 对象。回调函数以这种方式添加您的处理程序:

$.ajax({
    ...
    xhr: function() {
        // get the native XmlHttpRequest object
        const xhr = $.ajaxSettings.xhr();
        // set the onprogress event handler
        xhr.onprogress = function() {
            // replace the '#output' element inner HTML with the received part of the response
            $('#output').html(xhr.responseText);
        }
        return xhr;
    }
})
.done(function(data) {
    ...
})
.fail(function(data) {
    ...
});

current version中很难弄清楚XMLHttpRequest 标准,但是 archived one表示此事件大约每 50 毫秒或每收到一个字节就会触发一次,以频率最低的为准。

您应该对 JavaScript 代码进行的其他更改是

  • 取消注释 beforeSend 函数中的 $('#status').fadeIn('slow'); 行,并将其从其他函数中删除;
  • done 事件处理函数中删除 $('#output').append(data); 行,所有接收到的数据应该已经通过onprogress 处理函数。

最后但并非最不重要的部分是关于缓冲。我假设您正在将 nginx 与 PHP-FPM 一起使用,因为您将 nginx 标签添加到您的问题中。您已经使用了 flush()ob_flush() PHP 函数,您是对的,您需要这两个函数来刷新 PHP 缓冲区。然而,还有一种缓冲机制——nginx 本身。您可以使用 fastcgi_buffering off; 指令完全关闭 nginx FastCGI 缓冲,但这看起来不是一个好主意。幸运的是,nginx 允许通过特殊的 X-Accel-Buffering header 关闭响应缓冲,因此您的 AJAX PHP 处理程序应以

开头
<?php

header('Content-type: text/html; charset=utf-8');
header('X-Accel-Buffering: no');

...

关于php - PHP脚本输出的AJAX持续响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64680445/

相关文章:

javascript - pip.io UI 是在什么地方构建的?

php - 两个数据库上的两个事务

javascript - Ionic + Angular POST 请求返回状态 404

php - 有没有像必应图像搜索那样在悬停时扩展图像?

javascript - 使用 jquery 在 DOM 中查找位于单击元素之前的元素

javascript - 如何更改与其父 div 索引号相关的输入名称

JQuery 获取所选 Kendo Treeview 的所有父节点

javascript - 在javascript中触发自动回发

php - 解释基本的PHP Socket服务器代码

php - 如何捕获 MySQLi (PHP) 中的错误并继续执行?