XMLHttpRequest.upload.onprogress не работает с HTTPS - PullRequest
5 голосов
/ 21 апреля 2019

Выпуск

У меня есть страница, где пользователи могут загружать файлы с помощью FormData и XMLHttpRequest. Загрузка файла работает нормально. Но upload.onprogress - это только , работающий при загрузке из HTTP-соединения .

HTTPS

HTTPS

HTTP

HTTP

Я проверял это на Heroku и на экземпляре Amazon EC2. Но это всегда одно и то же:

  • Прогресс отображается при загрузке по HTTP
  • Событие прогресса никогда не запускается при загрузке по HTTPS

Javascript (Angular 7)

const xhr = new XMLHttpRequest();
let progress = 0;


/** THIS EVENT IS NOT WORKING WITH HTTPS */
xhr.upload.onprogress = (event: ProgressEvent) => {
    if (event.lengthComputable) {
        progress = 100 * (event.loaded / event.total);
    }
};


xhr.responseType = 'json';
xhr.open('POST', `${API_URL}/${this.API_PATH}/upload`, true);
xhr.setRequestHeader('authorization', this.authService.getAuthToken());
xhr.send(payload);
xhr.onload = () => {
    observer.next(xhr.response);
    observer.complete();
};

Node.js

const busboyBodyParser = require('busboy-body-parser');
app.use(busboyBodyParser())

const busboy = new Busboy({ headers: req.headers })
busboy.on('finish', async () => {

    const fileData = req.files.file
    const fileId = req.body.fileId
    const params = {
        Body: fileData.data,
        Bucket: awsConfig.bucket,
        ContentType: fileData.mimetype,
        Key: fileId,
        StorageClass: 'ONEZONE_IA',
    }
    awsConfig.s3.upload(params, (err, data) => { /* ... */ }

})
req.pipe(busboy)

Что я тоже пробовал

Я также пытался использовать синтаксис .addEventListener для прослушивания прогресса:

xhr.upload.addEventListener("progress", uploadProgress, false);

Но это тоже не сработало.

Исходный код

Node.Js (server.js)

Node.Js (upload-file.js)

Служба Angular (editor-file.service.ts)

Примечания

Обратите внимание, что я уже задавал вопрос по этой теме. Но я не получил рабочего ответа, и мне действительно нужно, чтобы это сработало.

Старый вопрос: Событие при загрузке XHR Событие не работает при подключении HTTPS

Ответы [ 2 ]

1 голос
/ 25 апреля 2019

Поскольку я пытался воспроизвести эту проблему, я не столкнулся с той же проблемой. Не могли бы вы проверить ниже простое приложение Heroku, которое я создал, чтобы проверить эту конкретную проблему? Кроме того, если есть какая-то недостающая часть, которую я не вижу, пожалуйста, сообщите мне.

Приложение Heroku для испытаний : https://erdsav -test-app.herokuapp.com /

Ниже приведен код JS , который я пытался построить поверх вашего кода, и он просто загружает данные zip и загружает их впоследствии (не может быть сохранен в Heroku из-за наличия Ephemeral файловая система) для обеспечения успешной загрузки файла;

import { Observable } from "../js/Observable.js";

document.addEventListener("DOMContentLoaded", function(event) {
    var progressBar = document.getElementById("progress"),
    fileNameSpan = document.getElementById("file_name"),
    fileSizeSpan = document.getElementById("file_size"),
    fileUploadComp = document.getElementById("file_upload"),
    loadButton = document.getElementById("upload_button"),
    displaySpan = document.getElementById("progress_display"),
    fileDetails = document.getElementById("file_details"),
    selectButton = document.getElementById("select_button"),
    formData = null;

    function hideElements(){
        fileDetails.style.display = "none";
    }

    function showElements(){
        fileDetails.style.display = "block";
    }

    function upload(payload, fileName){
        return new Observable(observer => {
            const xhr = new XMLHttpRequest();
            let progress = 0;

            /** THIS EVENT IS NOT WORKING WITH HTTPS */
            xhr.upload.onprogress = (event => {
                if (event.lengthComputable) {
                    progressBar.max = event.total;
                    progressBar.value = event.loaded;
                    progress = Math.floor((event.loaded / event.total) * 100);
                    displaySpan.innerText = progress + '%';
                    observer.next(progress);
                }
            });
            xhr.upload.onloadstart = function(e) {
              progressBar.value = 0;
              displaySpan.innerText = '0%';
            }
            xhr.upload.onloadend = function(e) {
              progressBar.value = e.loaded;
              loadButton.disabled = false;
              loadButton.innerHTML = 'Start Upload Process';
            }

            xhr.responseType = 'blob';
            xhr.open('POST', "https://erdsav-test-app.herokuapp.com/upload.php", true);  
            xhr.send(payload);
            xhr.returnedFileName = fileName;
            xhr.onload = () => {
                download(xhr.response, xhr.returnedFileName, "application/zip");
                observer.next(100);
                observer.complete();
            };
        });
    }

    function showUploadedFile(file){
        var fileName = file.name;
        var fileSize = file.size;

        fileNameSpan.innerText = fileName;
        fileSizeSpan.innerText = Math.floor(fileSize / 1000) + ' KB';
    }

    function buildFormData(file) {      
        if (formData) { 
            formData.append("file", file);
        }     

        return formData;  
    }

    hideElements(); 
    if (window.FormData) {
        formData = new FormData();
    }
    else{
        alert("FormData is not supported in this browser!");
    }

    fileUploadComp.onchange = function(){
        var file = fileUploadComp.files[0];

        if(file){
            showElements();
            showUploadedFile(file);
        }
        else{
            hideElements();
        }
    }

    selectButton.addEventListener("click", function(e){
       fileUploadComp.value = ""; 
       hideElements();    

       fileUploadComp.click();

       e.preventDefault(); 
    });

    loadButton.addEventListener("click", function(e) {
       if(fileUploadComp.files !== undefined && fileUploadComp.files.length > 0){
           this.disabled = true;
           this.innerHTML = "Uploading. Please wait...";

           var obs = upload(buildFormData(fileUploadComp.files[0]), fileUploadComp.files[0].name);
           obs.subscribe(
            function valueHandler(value){
              console.log("UPLOADING");
              if(value){
                  console.log(value);
              }
            },
            function errorHandler(err){
              console.log("THERE IS AN ERROR");
            },
            function completeHandler(){
              console.log("COMPLETE");
            }
            );
        }
        else{
            alert("No file is selected");
        }

        e.preventDefault();
    });
});

PHP сторона

<?php

if ($_FILES['file']['error'] != $UPLOAD_ERR_OK) {
    //writeLog($_FILES['file']['error']);
    echo 'An error occurred!'; 
    exit();
} 
else { 
   $filePath = $_FILES['file']['tmp_name'];
   $fileName = $_FILES['file']['name']; 

   if (file_exists($filePath)) {
        ob_start();
        $fileSize = readfile($filePath);
        $content = ob_get_clean();

        header('Content-Type: application/octet-stream;');
        header("Content-Disposition: attachment; filename=\"" . $fileName . "\"");
        header('Expires: 0');
        header('Pragma: no cache');
        header('Content-Length: ' . $fileSize);

        echo $content;
   }
   else{
       echo 'File is not found';
       exit();
   }
}

?>

Источник HTML-страницы

<!DOCTYPE html>
<html lang="en">
    <title>ProgressBar Progress Test</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="description" content="ProgressBar Progress Test">
    <body>          
            <form method="post" enctype="multipart/form-data">
                <input type="file" id="file_upload" accept="application/zip" style="width:0px" />
                <button id="select_button">Choose File to Upload</button>
                <progress id="progress" value="0"></progress>
                <span id="progress_display"></span>
                <button type="submit" id="upload_button">Start Upload Process</button>
            </form>
            <div id="file_details" style="display: none">
                <h3>Selected File Details</h3>
                <span id="file_name"></span><br>
                <span id="file_size"></span>
            </div>
            <script type="module" src="js/Observable.js"></script>  
            <script src="js/download.js"></script>  
            <script type="module" src="js/main.js"></script>                                
    </body>
</html>

Ниже изображение захвачено замедлением сети, чтобы увидеть текущий процент, пока процесс загрузки продолжается;

File Upload Test

Браузеры, использованные в тестировании;

Firefox Developer Edition 67.0b13 (64-разрядная версия / актуальная версия)
Google Chrome 74.0.3729.108 (64-разрядная версия / актуальная версия)

0 голосов
/ 30 апреля 2019

Я делаю то же самое с одним из моих веб-приложений, но без каких-либо углов, только с JS и PHP. Мой xhr работает как шарм и выглядит так:

var totalSize = 0;
var xhr = new XMLHttpRequest();    // den AJAX Request anlegen
xhr.open('POST', 'data/upload.php');    // Angeben der URL und des Requesttyps
xhr.upload.addEventListener("progress", handleProgress);
xhr.addEventListener("load", handleComplete);

и это мой метод handleProgess:

handleProgress = function(event){
    var progress = totalProgress + event.loaded;
    document.getElementById('progress').innerHTML = 'Aktueller Fortschritt: ' + ((progress - totalSize < 0) ? Math.floor(progress / totalSize * 10000) / 100 : 100)  + '%';
}
...