1

我遇到了与此处相同的问题:使用“Content-Range”标头按块上传视频文件,但给出的解决方案均不适合我。我正在使用 javascript 将视频放到 Vimeo 端点。我得到了一张上传票,并通过 php 在另一台服务器上处理上传的初始化和完成。javascript 所做的只是将视频数据放到一个端点上。

我的客户有一个不可靠的互联网连接,因此我正在构建一个尝试自动恢复的可恢复上传器。

我注意到的是,如果我删除“Content-Range”标题并将我的块大小设置为大于上传视频,它会正确上传。一旦我添加标题,事情就会出错。我知道标头应该采用“Content-Range”的形式:“bytes 1001-4999/5000”,但这会由于某种原因导致问题。当我使用这种格式时,chrome 不会发送“Content-Length”标头并且请求失败。FF 发送标头,但也失败了。

我为“Content-Range”标头尝试了不同的组合,包括:“1001-4999/5000”“range=1001-4999-5000”。这不会给出错误但 vimeo 无法识别,因为当我要求上传的字节时,我总是得到最后上传的块的长度。我也尝试过发送没有标头的第一个块,其余的都带有它,但它是标头本身没有被正确发送。

Javascript:

/*
 * Uploads raw data to the server
 *
 */
var uploadRawData = function(starting_byte, ending_byte, data_to_send){
    $('.auto_uploader #play_pause_button').addClass('pause').removeClass('disabled');
    $('.auto_uploader #stop_button').removeClass('disabled');
    $('.auto_uploader #status_display').attr('class', '').fadeIn(); //Remove all other classes
    _offset_starting_from = parseInt(starting_byte) || 0;

    _uploader_process = $.ajax({
        url: _endpoint,
        type: 'PUT',
        beforeSend: function (request)
        {
            //if (starting_byte != 0){ // Send the first chunk with without content-range header
                // If this function is being called to resume a file, add the starting offset
                var content_range_header = "bytes " + starting_byte + "-" + ending_byte + "/" + _file.size;
                request.setRequestHeader("Content-Range", content_range_header);
            //}
            request.setRequestHeader("Content-Type", _file.type);
            //request.setRequestHeader("Content-Length", data.byteLength);
        },
        processData: false,
        xhr: function() {  // custom xhr
            myXhr = $.ajaxSettings.xhr();
            if(myXhr.upload){ // check if upload property exists
                myXhr.upload.addEventListener('progress', progressHandlingFunction, false); // for handling the progress of the upload
            }
            return myXhr;
        },
        //Ajax events
        success: function() {
            if (ending_byte < _file.size - 1){ // Not complete (chunk mode)
                var next_upload_byte = ending_byte + 1;
                retryUpload(); // Check for uploaded bytes before next chunk upload (this creates an infinite loop since vimeo only reports the last byte uploaded, since the Content-Range header above is not being recognised) - Or
                //uploadFilePart(next_upload_byte, next_upload_byte + _chunk_size - 1); // - doesn't check uploaded bytes before send of next chunk (Uploads all parts, but vimeo only registers the last chunk)
            } else { // Complete!
                //retryUpload(); // Check to make sure the entire file was uploaded
                $('.auto_uploader #status_display').attr('class', 'tick');
                resetButtons();
                _completeFunction(); //Call user defined callback
            }
        },
        error: function(data) {
            console.log(data.responseText);
            if (!_paused && _file != null){ //Aborting (pausing) causes an error
                // Retry the upload if we fail
                if (_retry_count < _retry_limit){
                    _retry_count = _retry_count + 1;
                    console.log('Error occurred while uploading file "' + _file.name + '",  retry #' + _retry_count + ' in ' + _retry_count * 10 + ' sec');
                    setTimeout(function() {   //calls click event after a certain time
                        retryUpload(); // Call the retry upload method in 10 sec
                    }, 10000);
                } else if (_retry_count == _retry_limit){
                    //We've tried enough!});
                    resetButtons();
                    $('.auto_uploader #status_display').attr('class', 'error');
                    alert('Maximum number of retries exceeded!');
                }
            }
        },
        //error: errorHandler,
        // Form data
        data: data_to_send,
        //Options to tell JQuery not to process data or worry about content-type
        cache: false,
        contentType: false
    });
}

我在这里上传了一个测试版本: http: //test.paperjet.info/auto_uploader/和完整的源代码:http: //test.paperjet.info/auto_uploader.zip标题被添加到autoUploader 的第 121 行。 js。请注意,如果您使用它,它有一个硬编码到 index.html 的端点,并且可能已经过期。

如果有人解决了这个问题或已经使用javascript成功实现了这个功能,请告诉我。

4

2 回答 2

2

我遇到了同样的问题,并设法在 Github 上构建了一个将视频文件按块上传到 Vimeo 的实现:https ://github.com/websemantics/vimeo-upload

它使用可恢复的 PUT 并显示进度条并返回上传视频的 url。

于 2014-12-25T06:32:10.990 回答
0

在服务器上获取字节的正确方法是Content-Range: bytes */*在请求标头中执行 PUT:

var byte_request = new XMLHttpRequest();
byte_request.open('PUT', upload_url, true);
byte_request.overrideMimeType('application/octet-stream');
byte_request.setRequestHeader('Content-Range', 'bytes */*');
byte_request.send();

这应该返回 308 响应。在您的成功处理程序中,转义Range标题:

function onByteRequestSuccess(e) {
    var range_header,
        bytes_received;

    if (byte_request.status === 308) {
        range_header = xhr.getResponseHeader('Range');

        // The Range header will return something like "bytes=0-215235".
        // This grabs the group of numbers AFTER the "-" character,
        // which is the total bytes on the server.
        bytes_received = parseInt(range_header.split('-')[1], 10);
    }
}

至于您的Content-Type标头不会出现,我发现大多数库(jQuery 和 MooTools)对于此类请求都不可靠。如果您仍然遇到问题,可能需要更深入地研究 jQuery 的代码库。

于 2013-04-04T17:06:13.813 回答