Issue
I have a page where users can upload files with the help of FormData
and an XMLHttpRequest
.
Uploading the file works fine. But the upload.onprogress
is only working when uploading from an HTTP connection.
HTTPS
HTTP
I've tested this on Heroku and on an Amazon EC2 instance. But it's always the same:
- Progress is shown when uploading via HTTP
- Progress event is never triggered when uploading via 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);
observerplete();
};
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)
What I've also tried
I also tried to use the .addEventListener
syntax for listening for progress:
xhr.upload.addEventListener("progress", uploadProgress, false);
But this didn't work, either.
Source Code
Node.Js (server.js)
Node.Js (upload-file.js)
Angular Service (editor-file.service.ts)
Notes
Please note, that I have already asked a question about this topic. But I got no working answer and I really need this to work.
Old question: XHR upload onprogress Event not Working on HTTPS Connection
Issue
I have a page where users can upload files with the help of FormData
and an XMLHttpRequest
.
Uploading the file works fine. But the upload.onprogress
is only working when uploading from an HTTP connection.
HTTPS
HTTP
I've tested this on Heroku and on an Amazon EC2 instance. But it's always the same:
- Progress is shown when uploading via HTTP
- Progress event is never triggered when uploading via 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)
What I've also tried
I also tried to use the .addEventListener
syntax for listening for progress:
xhr.upload.addEventListener("progress", uploadProgress, false);
But this didn't work, either.
Source Code
Node.Js (server.js)
Node.Js (upload-file.js)
Angular Service (editor-file.service.ts)
Notes
Please note, that I have already asked a question about this topic. But I got no working answer and I really need this to work.
Old question: XHR upload onprogress Event not Working on HTTPS Connection
Share Improve this question edited Apr 25, 2019 at 8:43 Florian Ludewig asked Apr 21, 2019 at 13:07 Florian LudewigFlorian Ludewig 5,98216 gold badges83 silver badges154 bronze badges 6- 1 Possible duplicate of XHR upload onprogress Event not Working on HTTPS Connection – Jordan Kasper Commented Apr 21, 2019 at 13:51
- 1 Yes, I've mentioned it at the bottom of this question :) – Florian Ludewig Commented Apr 21, 2019 at 17:40
- 2 Yes, and asking the same question is typically discouraged on StackOverflow. That comment is actually an automated response from the identification of duplication. – Jordan Kasper Commented Apr 21, 2019 at 21:07
- 1 (But I do hope you find the answer, it's a weird problem.) – Jordan Kasper Commented Apr 21, 2019 at 21:07
- You can try fetch with progress stackoverflow.com/questions/35711724/… – Alex Nikulin Commented Apr 25, 2019 at 5:17
5 Answers
Reset to default 8It's important to set Listener between:
xhr.open('POST'...);
...put you listener here....
xhr.send(data)
In this case it gonna work!
I'm doing just the same with one of my webapps but without any angular, just JS and PHP. My xhr works like a charm and is looking like this:
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);
and this my handleProgess method:
handleProgress = function(event){
var progress = totalProgress + event.loaded;
document.getElementById('progress').innerHTML = 'Aktueller Fortschritt: ' + ((progress - totalSize < 0) ? Math.floor(progress / totalSize * 10000) / 100 : 100) + '%';
}
As I've tried to reproduce this problem, I didn't face the same issue. Could you please check below simple Heroku app that I've created to test this specific problem? Also, if there is any missing part that I am not seeing, please inform me.
Heroku Test-Purpose App: https://erdsav-test-app.herokuapp.com/
Below is the JS code that I am tried to build on top of your code and it simply uploads the zip data and downloads it afterwards (cannot store on Heroku because of having Ephemeral filesystem) to ensure that the file is uploaded successfully;
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 side
<?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 page source
<!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>
Below image is captured by slowing the network to see the current percentage while uploading process continues;
Browsers used in testing;
Firefox Developer Edition 67.0b13 (64-bit/Up-to-date)
Google Chrome 74.0.3729.108 (64-bit/Up-to-date)
Now in 2022
The 2016's specifications are outdated, here is the new standard for XMLHttpRequest.
The upload is a getter that returns an XMLHttpRequestUpload object
The XMLHttpRequestUpload object implements the XMLHttpRequestEventTarget interface, which handles the onprogress event.
Now here's what MDN says about this:
Note: The spec also seems to indicate that event listeners should be attached after open(). However, browsers are buggy on this matter, and often need the listeners to be registered before open() to work.
I've had the same issue. The point was in my service worker, which only acts with https. Namely I had wrong the 'fetch' event listener.