XMLHttpRequest.upload.onprogress不适用于HTTPS

时间:2019-04-21 13:07:52

标签: javascript node.js https xmlhttprequest busboy

问题

我有一个页面,用户可以在FormDataXMLHttpRequest的帮助下上传文件。 上传文件效果很好。但是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 Service (editor-file.service.ts)

注释

请注意,我已经问过有关此主题的问题。但是我没有有效的答案,我真的需要这个。

旧问题:XHR upload onprogress Event not Working on HTTPS Connection

3 个答案:

答案 0 :(得分:1)

在尝试重现此问题时,我没有遇到相同的问题。您能否检查下面我为测试此特定问题而创建的简单Heroku应用程序?另外,如果我看不到任何缺失的部分,请通知我。

Heroku测试目的应用程序https://erdsav-test-app.herokuapp.com/

下面是我尝试在您的代码之上构建的 JS代码,它只是上传zip数据并随后下载(由于具有 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位/最新)

答案 1 :(得分:0)

我正在使用一个我的web应用程序执行相同的操作,但是没有任何角度,只是JS和PHP。 我的xhr就像一个护身符,看起来像这样:

<div class="col-lg-3 col-xs-6" id="div1">
  <div class="form-group" id="divType">
    <label>Templte Type:</label>
    <select class="form-control" id="ftype">
      <option value="..All">..All</option>
      <option value="Functional">Functional</option>
      <option value="Non Functional">Non Functional</option>
    </select>
  </div>
</div>

这是我的handleProgess方法:

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);

答案 2 :(得分:0)

在以下位置设置侦听器很重要:

xhr.open('POST'...);

...put you listener here....

xhr.send(data)

在这种情况下它将起作用!