【问题标题】:Tell AJAX that the request was completed without canceling file upload告诉 AJAX 请求已完成,无需取消文件上传
【发布时间】:2016-09-04 17:57:02
【问题描述】:

如果标题具有误导性,我很抱歉,没有简单的方法可以在标题中删减我的问题。我目前正在尝试 AJAX 文件上传;我之前已经完成了标准文件上传,但现在我试图通过添加一个进度条来使我的应用程序界面更好一点,该进度条跟踪文件上传进度并在视频完成上传、完成处理并放入数据库时​​通知用户。

除了 Ajax 当前正在为我的脚本完成执行之外,它工作得很好。基本上,发生的情况是大多数调用都是从一个名为uploadfiles.php 的文件中进行的。我正在使用带有feof 的while 循环并将进度记录到文件中,然后应该由另一个循环的AJAX 获取该文件,直到文件告诉它请求已更改/完成。

但是,由于某种原因,进度条不会移动,因为第一个 AJAX 请求一直在等待 uploadfiles.php 完全执行完 (这将是文件完成上传、处理并被移动的时候,并且会使进度条毫无意义),因此不会让下一个检索日志文件内容的 AJAX 请求。我尝试了以下方法:

  • ob_start(); and ob_end_flush() 是在文件从 PHP 的 tmp 文件夹移动到我的自定义 tmp 文件夹之后完成的
  • 做了flush(),我想这和上面的点完全一样
  • 随机回应某事并再次刷新,希望会发生一些事情

我还添加了ignore_user_abort() 以确保在用户离开页面/请求结束或中止时请求不会中止。

**这里是JS代码:

    function uploadFiles()
{
    var data2 = new FormData($("#specialform")[0]);

    timestamp = new Date().getUTCMilliseconds();
    timestamp = timestamp.toString();

    data2.append('outputId', timestamp);

    console.log(data2);

    $.ajax({
        type        : "POST",
        url         : "actions/uploadfiles.php",
        data        : data2,
        processData : false,
        contentType : false,
        success: function(data)
        {
            alert('Finished first request');
            getLog();
        },
        error: function (xhr, ajaxOptions, thrownError)
        {
            alert(xhr.responseText);
            alert(thrownError);
        },
        xhr: function ()
        {
            var xhr = new window.XMLHttpRequest();

            xhr.addEventListener("progress", function (evt)
            {
                if (evt.lengthComputable)
                {
                        var percentComplete = evt.loaded / evt.total;
                        console.log(percentComplete);
                        var percentComplete = percentComplete * 100;

                        $("#progressBar").css({ width : percentComplete + '%' });

                        if ( percentComplete >= 100 )
                            xhr.abort();
                }
                else
                        console.log('unable to complete');
            }, false);

            return xhr;
        },
    })
    .fail(function(data)
    {
        console.log(data);
    });

    //return {'error' : 'No files', 'result' : null};
}

function getLog()
{
    if ( finished == false )
    {
        console.log("logs/" + timestamp);

        $.ajax({
            type        : "GET",
            url         : "logs/" + timestamp,
            processData : false,
            contentType : false,
            success: function(data)
            {
                if ( data == "processing" && !processed )
                {
                    alert('processing video');

                    $("#progressBar").css({ 'background-color' : 'yellow' });

                    processed = true;
                }

                if ( data == "done" )
                {
                    alert('finished conversion');

                    $("#progressBar").css({ 'background-color' : 'green' });

                    finished = true;
                }

                if ( $.isNumeric(data) )
                    $("#progressBar").css({ width : data + '%' });

                console.log(data);
            }
        });

        setTimeout(getLog, 1000);
    }
}

这是 PHP 代码:

<?php

require '../Init.php';

define('TMP_PATH', PATH.'/tmp');
define('V_STORE', PATH.'/resources/videos');
define('FFMPEG_PATH', 'F:/Webserver/ffmpeg/bin/ffmpeg.exe');

// ...

ob_start();

echo "END";

ob_end_flush();
flush();

// ...

$remote = fopen($_FILES['file']['tmp_name'], 'r');
$local = fopen($filename, 'w');

$read_bytes = 0;

set_time_limit(28800000);
ignore_user_abort(true);

$interval = 0;

while( !feof($remote) )
{
    $buffer = fread($remote, 2048);
    fwrite($local, $buffer);

    $read_bytes += 2048;

    $progress = min(100, 100 * $read_bytes / $filesize);

    if ( $interval <= 0 )
    {
        file_put_contents('../logs/'.$logFile, $progress);

        $interval = 1000;
    }
    else
        $interval--;
}

// ...

$proc = popen(FFMPEG_PATH.' -i '.$filename.' -b '.$newBitrate.' '.V_STORE.'/'.$video_id.'.mp4', 'r');

while (!feof($proc))
{
    file_put_contents('../logs/'.$logFile, fread($proc, 4096));
}

file_put_contents('../logs/'.$logFile, "done");

sleep(5);

unlink('../logs/'.$logFile);

不要担心Init.php 因为(在这种情况下)它只用于PATH 常量

提前致谢。

【问题讨论】:

  • 在您的问题中发布相关代码。
  • 代码很长,你确定吗? @迈克
  • 我添加了 pastebin 链接
  • 这就是我说“相关”的原因

标签: php jquery ajax feof


【解决方案1】:

您是否在 Init.php 文件(或其他地方)中使用基于 PHP 文件的会话?默认情况下,这些文件会锁定,直到会话有效关闭,一次只允许执行一个请求。

如果是这样,您需要使用以下命令关闭上传文件中的会话:

session_write_close();

【讨论】:

  • 刚刚试了一下,不幸的是它确实产生了与前面提到的结果不同的结果:(
  • 添加一个标头表明文件是纯文本并在进度为 100 时中止 XHR 请求解决了这个问题,但我相信这也有帮助:) 谢谢
猜你喜欢
  • 2021-08-27
  • 1970-01-01
  • 1970-01-01
  • 2011-07-17
  • 2017-11-14
  • 2016-06-11
  • 2014-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多