XMLHttpRequest in google-chrome is not reporting progress events - javascript

Hi all I have this code:
function test()
{
req = new XMLHttpRequest();
req.upload.addEventListener("progress", updateProgress, false);
req.addEventListener("readystatechange", updateProgress, false);
req.addEventListener("error", uploadFailed, false);
req.addEventListener("abort", uploadCanceled, false);
var data = generateRandomData(currentPayloadId);
totalSize = data.length;
req.open("POST", "www.mydomain.com/upload.aspx");
start = (new Date()).getTime();
req.send(data);
}
function updateProgress(evt)
{
if (evt.lengthComputable) {
total = totalSize = evt.total;
loaded = evt.loaded;
}
else {
total = loaded = totalSize;
}
}
Also, my server responds to the initial OPTIONS request for upload.aspx with 200 and the Access-Control-Allow-Origin: *
and then the second request POST happens
Everything seems in place and it's working great on FireFox but on G Chrome the updateProgress handler is not getting called but only once and then the lengthComputable is false.
I needed the Access-Control-Allow-Origin: * because this is a cross-domain call, the script parent is a resource on a different server then the upload.aspx domain
Anyone can give me some clues, hints, help please? is this a known issue with G Chrome?
Thank you!
Ova

I think I have a solution for your problem
I don't know what is behind this function "generateRandomData()"
var data = generateRandomData(currentPayloadId)
It is working when I change into this:
var data = new FormData();
data.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
Small explanation: You need manually to append to form data an file input form, where fileToUpload is <input type="file" name="fileToUpload" id="fileToUpload" />
And in your updateProgress function in IF part you can add something like this to track progress console.log(evt.total +" - "+ evt.loaded)
This is working in Google Chrome browser. I have tested in new browser version 57
I made for myself an upload progress form 4 years ago, which means that this code is working in old browser version too.
A whole code snippet will be looking like this
function test()
{
req = new XMLHttpRequest();
req.upload.addEventListener("progress", updateProgress, false);
req.addEventListener("readystatechange", updateProgress, false);
req.addEventListener("error", uploadFailed, false);
req.addEventListener("abort", uploadCanceled, false);
//var data = generateRandomData(currentPayloadId);
var data = new FormData();
data.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
totalSize = data.length;
req.open("POST", "www.mydomain.com/upload.aspx");
start = (new Date()).getTime();
req.send(data);
}
function updateProgress(evt)
{
if (evt.lengthComputable) {
total = totalSize = evt.total;
loaded = evt.loaded;
console.log(evt.total +" - "+ evt.loaded)
}
else {
total = loaded = totalSize;
}
}

I had this problem when the page your are loading doesn't contain a
Content-Length: 12345
in the header, where 12345 is the length of the response in bytes. Without a length parameter, the progress function has nothing to work on.

First, make sure that "www.example.com" is added to the manifest.json, like so:
manifest.json
{
..
"permissions": [
"http://www.example.com/",
"https://www.example.com/",
],
..
}
Then I think your example should work.
For more information about using xhr in google chrome extensions the docs are here.
Also the CSP docs are worth taking a look at if what I provided above does not.

This could simply be a compatibility issue with the XMLHttpRequest.upload property. It returns an XMLHttpRequestUpload object, but if you try find that object spec in MDN it doesn't exist so how do we know which browsers fully support it.
XMLHttpRequest.upload Compatability
Have you tried listening for progress directly on the xhr:
req.addEventListener("progress", updateProgress, false);

I use jQuery for progress like that:
$.ajax({
url : furl,
type : method,
data : data,
//...
},
xhr : function () {
//upload Progress
var xhr = $.ajaxSettings.xhr();
if (xhr.upload) {
xhr.upload.addEventListener('progress', function (event) {
var percent = 0;
var position = event.loaded || event.position;
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
//update progressbar
$(".progress-bar").css("width", + percent + "%");
$(" .status").text(position + " / " + total + " (" + percent + "%)");
}, true);
}
return xhr;
},

Related

XMLHttpRequest sends url as response text, Firefox doesn't redirect

I have some javascript that sends a XMLHttpRequest to a PHP file. This PHP file sends a response, and javascript is supposed to create a URL and redirect to it, using the response text as a parameter. In all other browsers it works fine, but Firefox won't include the response text in the URL.
This is the javascript example:
var xhr = new XMLHttpRequest();
xhr.open('POST', 'filename.php', true);
xhr.onreadystatechange = function(e){
var id = e.currentTarget.responseText;
var urlWithId = "restofurl?id=" + id;
window.location.href = urlWithId;
}
xhr.send(fd);
and filename.php is just a number at the moment:
<?php
echo "3";
?>
I have tried putting other parts of the url (up to the whole url) in the php part, and firefox always cuts out exactly that part. I have also tried copying the response several times to different variable, copying it character by character, putting it in a function that just returns the input again,...
This is only going to be on my own computer, so I don't need to worry about any security issues, so I'm mostly looking for an easy way to cheat around this rather than the way it would be done professionally. Does anyone have any idea?
This is a basic example, you actually have to test readyState status. If i remember well, it is also safer to set the event function before sending the request (not really sure of that).
xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4) {
//do something with this.responseText
}
};
xhr.open("POST", url, true);
xhr.send();
EDIT:
This is one of the reasons why i use frameworks, for the old browser support, but this is not an answer. To be more precise, in the past (present?), browsers used to implement exotic functions. It's been a long time i didnt bother to use XHR objects directly, last time it was for file uploads with loading bar (canvas). It shows you the basic way to handle some stuff. This is longer and a bit old fashioned, but well, it works.
function customXHR(){
if(window.XMLHttpRequest){
return new window.XMLHttpRequest;
}else{
try{ //the weird ones
return new ActiveXObject("MSXML2.XMLHTTP.3.0");
}
catch(ex){
return null;
}
}
}
var xhr = customXHR(), pleaseStop = false, startDraw = false;
if(xhr){
xhr.addEventListener('load', function(e){
var jsonRep;
if(!pleaseStop){
//did use a JSON response
jsonRep = $.parseJSON(e.target.responseText);
//do the rest, we finished
}
}, false);
xhr.addEventListener('error', function(e){
//error
pleaseStop = true;
}, false);
xhr.upload.addEventListener('progress', function(e){
//why not let this as an example!
//file_size must be retreive separately, i fear
if(e.lengthComputable && file_size > 0 && !pleaseStop && startDraw){ draw_progress(e.loaded / file_size); }
}, false);
xhr.addEventListener('loadstart', function(e){
//can be used too
}, false);
xhr.addEventListener('readystatechange', function(e){
if(e.target.status == 404 && !pleaseStop){
//error not found
pleaseStop = true;
}
if(e.target.readyState == 2 && e.target.status == 200){
startDraw = true;
}
/*if(e.target.readyState == 4){
//not used here, actually not exactly the same as 'load'
}*/
}, false);
xhr.open("POST", url, true);
xhr.send();
} //else no XHR support

Progress bar for multiple ajax requests with stages of completion. Is it possible?

I have a simple form which when submitted validates via an ajax request. If the form checks out ok, then another ajax request is made to process the data originally submitted.
I want to build a progress bar for this. Ive found that adding this code to each ajax request returns the progress for each call separately. That makes the progress bar load to 100%, twice, quickly.
Is it possible for example for two ajax request to each fill 50% of the progress bar?... So ajax request 1 will fill up to 50% and the second will fill from 51% to 100%? Or is that crazy?
Or if three ajax calls each being responsible for 33.33% of the total percentage?
I guess we are more looking at stages of completion as well as progress.
Any ideas how this could be achieved without too much faking it?
var xhr = new window.XMLHttpRequest();
//Upload progress
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with upload progress
console.log('percent uploaded: ' + (percentComplete * 100));
}
}, false);
//Download progress
xhr.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with download progress
console.log('percent downloaded: ' + (percentComplete * 100));
}
}, false);
return xhr;
Well the way i had created such a progress bar was, since you want each of your function to be called one after another, that is completion of one should trigger the other, XMLHttpRequest has onreadystate change event. you can use that event to confirm that the first request got executed successfully or not, and then trigger the second one, at each change you will have progress bar incremented by whatever % you want to.
function postdata()
{
var xhr = new XMLHttpRequest();
xhr.open
(
"POST",
Url,
true
);
xhr.send();
xhr.onreadystatechange = function()
{
if (xhr.readyState == 4)
{
//Call next function here and increment progressbar
}
}
}
hope this helps
Yes, it is possible. You can create an array containing each ajax call. Set <progress> element max attribute to 100/array.length. Divide evt.loaded / evt.total of individual progress event by array .length to set value of <progress> element. You could also use Promise.all(), .then() to process array of functions returning a Promise from ajax call and update <progress> element.
html
<label></label>
<progress value="0" min="0" max="100"></progress>
javascript
var progress = document.querySelector("progress");
var url = "/echo/html/";
function request(url) {
var len = arr.length;
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = ((evt.loaded / evt.total) * (progress.max / len))
/ len;
progress.value += percentComplete;
console.log(progress.value, percentComplete);
if (evt.total === evt.loaded) {
requests += 1;
}
if (progress.value == progress.max && requests === len) {
progress.previousElementSibling.innerHTML = "upload complete";
// you could call `resolve()` here if only interested in
// `upload` portion of request
alert("upload complete");
}
}
}, false);
xhr.onload = function() {
resolve(this.responseText)
};
xhr.onerror = reject;
xhr.open("POST", url, true)
xhr.send("html=" + Array(100000).fill(1).join(""));
})
}
var arr = [], requests = 0;
arr.push(request, request, request);
Promise.all(arr.map(function(req) {
return req(url)
}))
.then(function(data) {
console.log(data);
})
.catch(function(err) {
console.log(err)
})
jsfiddle https://jsfiddle.net/v2msL7hj/3/

xmlhttprequest special send

I would like to seek your help about xmlhttprequest. I would like to perform xmlhttp request sending out to get pictures repeatly from server only when the previous http response is received.
In server side, I have created http responses which tagged with xmlhttp status =900.So I want to send out the request once the response due to previous request is received, otherwise, the program should wait until its arrival.
For example:
When I press the button somewhere in the browser, it triggers first picture (jpeg) request to server, then waiting the server's response. After getting the Http response with status marked as 900, xmlhttp will decode the response and display the picture on (image).
In the following code, by capturing the packet with wireshark, I think I success to get the right packet flow. However, the picture can not be shown in the DIV.
Can anyone help me ? Thanks a lot and a lot!
enter code here
function init(url)
{
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET',url,true);
xmlHTTP.send();
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e)
{
var arr = new Uint8Array(this.response);
var raw = String.fromCharCode.apply(null,arr);
var b64=btoa(raw);
var dataURL="data:image/jpeg;base64,"+b64;
document.getElementById("image").src = dataURL;
};
xmlHTTP.onreadystatechange=function(){
buff(xmlHTTP.status);
}
}
buff(status){
if (status=900){
sleep(1000);
init('/images/photos/badger.jpg');
}
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
</script>
</head>
<body>
<div id="image"><h2>picture display here</h2></div>
<button type="button" onclick=buff(900)>Get Picture</button>
enter code here
There are several problems with your code.
Markup
The problem with your markup is, that you are using a div tag to display an image. The src attribute is not supported on div tags. You should use an img tag instead like this:
....
<img id="image" />
<button type="button" onclick="buff(900)">Get Picture</button>
Statuscode
Why are you using a status of 900? If the request was correct and the image was loaded, please use a status of 200.
Image loading
Why are you even using an XMLHttpRequest for loading images?
You could simply change the src attribute on the img tag and the browser will request the image.
If you want to reload the image you could just refresh the src attribute. If all images a served under the same URL, you can add a request param like the current time:
document.getElementById("image").src = "/images/photos/badger.jpg#" + new Date().getTime();
This way the browser will request the image again and won't use the one allready loaded and cached. See this answer for further info. (Actually the question is nearly the same as yours...)
Sleep function
Your sleep function will use resources because it's a loop that will constantly run for the specified time. While it runs, it will add numbers and do comparisons that are completly unnecessary.
please use something like the javascript build in setTimeout():
buff(status) {
if(status === 900) {
setTimeout(funciton(){
init('/images/photos/badger.jpg');
}, 1000);
}
}
Update: working example
I set up a working example in the code snippet. It loads images from the same url, but they are served randomly on each request by lorempixel.
I reorganized the image loading. Actually there was another problem. You startet the next image loading with onreadystatechange. This will fire for each change of the readystate and not only when the image is loaded. Therefore I start the next buff() from the onload() like so:
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET',url,true);
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e) {
var arr = new Uint8Array(this.response);
var raw = String.fromCharCode.apply(null,arr);
var b64 = btoa(raw);
var dataURL = "data:image/jpeg;base64," + b64;
document.getElementById("image").src = dataURL;
buff(this.status);
};
xmlHTTP.send();
For convenience I added a button for stopping the loading of new images.
For your example you just have to change the imageUrl and imageStatus variables.
var imageUrl = "http://lorempixel.com/400/200/", // set to "/images/photos/badger.jpg" for your example
imageStatus = 200, // set to 900 for your example
stopped = true;
function stopLoading() {
stopped = true;
}
function loadNextImage(url) {
if(!stopped) { // only load images if loading was not stopped
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET',url,true);
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e) {
var arr = new Uint8Array(this.response);
var raw = String.fromCharCode.apply(null,arr);
var b64 = btoa(raw);
var dataURL = "data:image/jpeg;base64," + b64;
document.getElementById("image").src = dataURL;
buff(this.status); // set the next timer when the current image was loaded.
};
xmlHTTP.send();
}
}
function buff(status) {
if (status === imageStatus) {
setTimeout(function() {
loadNextImage(imageUrl + "?" + new Date().getTime());
}, 1000);
} else {
// Status does not match with expected status.
// Therefore stop loading of further images
stopLoading();
}
}
function init() {
stopped = false;
loadNextImage(imageUrl);
}
document.getElementById("start").onclick = function(){
init(imageUrl);
};
document.getElementById("stop").onclick = stopLoading;
<img id="image" />
<button type="button" id="start">Get pictures</button>
<button type="button" id="stop">No more pictures</button>

Extract URL data from XMLHttpRequest

here is my javaScript code:
window.addEventListener('load', function() {
var submitimages = document.getElementById('submitimages');
submitimages.addEventListener('click', upload);
var images = document.getElementById('images');
});
var upload = function(event) {
event.preventDefault();
event.stopPropagation();
var data = new FormData();
for(var i = 0; i < images.files.length; ++i) {
data.append('images[]', images.files[i]);
}
var xhr = XMLHttpRequest();
xhr.open('POST', 'upload.php?test=' + 'test', true);
xhr.send(data);
}
My objective is to upload multiple images using form data and I want those sent images to move on a different directory depending on text that is on the url upload.php?test=' + 'test' where as on my example I want to move those image to test folder
and here is my php code so far
Please help I tried everything I know but I think I need idea whos someone is more knowledgeable to JavaScript. Regards

html convert text data to file and upload it

Is it possible with javascript to convert text from text-input and upload it as a file to server? I need to add to page something like text editor to open text file, then change it and upload to server as file but not as value of parameter in post request.
So is it possible to do?
Thanks.
If the browser supports XMLHttpRequest 2 (see http://caniuse.com/xhr2), you have an option.
The Uploading a file or blob: xhr.send(Blob) section of the HTML5 Rocks Tutorial (New Tricks in XMLHttpRequest2) has some sample code to get you started:
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
// Listen to the upload progress.
var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progressBar.value = (e.loaded / e.total) * 100;
progressBar.textContent = progressBar.value; // Fallback for unsupported browsers.
}
};
xhr.send(blobOrFile);
}
upload(new Blob(['hello world'], {type: 'text/plain'}));

Categories