I will try to explain my problem very detailed.
NOTE-1: It is not an issue with small files or whatever. I'm testing it with large files, with slow upload speed network
throttling...etc
NOTE-2: The progress bar works perfectly in other browser (Tested in edge)
NOTE-3: This issue only occurs in CHROME browser
I'm currently working on a file Uploader by using XHR. Everything works good, files are upload ...etc
I made a progress bar which its working, but only the very first time. (Or when I do CTRL+SHIFT+R), which basically clears the cache. (I have even ticked clear cache in developer mode which is active during testing)
As I said, it works the very first time, however, when I refresh the page, the progress even is not fired. However, load event is fired (This event is only fired when the file is fully uploaded)
I tested the code and everything is working fine in Edge browser, I can refresh and progress event is fired correctly, however is not the same for Chrome.
I have read some articles about that content-length must exists in headers and be greater than zero, and it is.
This is my script (The upload part)
let uploadFile = () => {
//... Some other stuffs
console.log("Upload started")
let xhr = new XMLHttpRequest();
let formData = new FormData();
formData.append('file', file);
xhr.open("POST", "uploaderServerside.php");
xhr.upload.addEventListener('progress', function(evt){
console.log("Uploading: " + (Math.round(evt.loaded / evt.total * 100)) + "%");
}, false);
xhr.addEventListener("load", () => {
console.log("Upload finished")
});
xhr.send(formData);
}
I hope you can bring me a hand with this issue, thanks for reading and best regards.
Sound like chrome has some aggressive caching, you can check the network tab to see if the request is loaded from cache, you will see (disk cache) under the size column.
To avoid the cache you can use a cache buster
xhr.open("POST", "uploaderServerside.php?_="+(new Date()).getTime());
Or you can set Headers on uploaderServerside.php to force the browser to not cache the request like
Cache-Control: no-store
Expires: 0
Related
I upload a file via a form to the webserver but when completed the response is somehow not being displayed, even though if I check the developer status tools (in Chrome/Firefox) it is getting returned.
Originally I was just using a form & post but have since switched to trying to provide a JS solutuion as the files are large & I want to display upload progress & time expected to complete
$form.on('submit', function(e) {
e.preventDefault();
if (isAdvancedUpload) {
let formData = new FormData(document.forms.upload);
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.upload.addEventListener('progress', updateProgress);
xhr.open('POST', '/load', true);
xhr.send(formData);
}
In all browsers this uploads the file but response is never displayed (even though in developer / network / response the full HTML is returned)
If I do NOT use e.preventDefault(); it works as expected but only in Chrome (not Safari & Firefox)
This is the console stack trace at the end (My script ends with a 302 redirect and a GET request on original script -- required behaviour)
XHR GET https://************.com/load [HTTP/2.0 200 OK 42ms]
<anonymous> https://***************.com/js/uploader.js:86:8
dispatch https://code.jquery.com/jquery-3.4.1.min.js:2:42571
add/v.handle https://code.jquery.com/jquery-3.4.1.min.js:2:40572
Any pointers please?
Ok am working on a laravel web project, I have written this code(which I learned online) to upload video and photos. This code works fine when uploading pictures because they are light. But when it gets to videos it works fine for light videos but tries to freeze the browser for videos above 30MB. The most annoying part is that when I tried uploading(picture or video) from mobile the device complained 'Failed to complete operation due to low memory' the fact that this code freezes the browser for heavy videos and and complains of memory on mobile means its not good enough(portable). Please I will appreciate having a better snippet of code to do the job(jQuery welcomed).
Here is what I have
function uploadPhoto(url, photo) {
var token = $('#token').val();
var formData = new FormData();
formData.append('photo', photo);
formData.append('_token', token);
var ajax = new XMLHttpRequest();
ajax.upload.addEventListener('progress', progressHandler, false);
ajax.addEventListener('load', completeHandler, false);
ajax.addEventListener('error', errorHandler, false);
ajax.addEventListener('abort', abortHandler, false);
ajax.open('POST', url);
ajax.send(formData);
}
function uploadVideo() {
var route = $('#uploadUrl').val();
var token = $('#token').val();
var video = document.getElementById('postVideo').files[0];
var formData = new FormData();
formData.append('video', video);
formData.append('_token', token);
var ajax = new XMLHttpRequest();
ajax.upload.addEventListener('progress', progressHandler, false);
ajax.addEventListener('load', completeHandler, false);
ajax.addEventListener('error', errorHandler, false);
ajax.addEventListener('abort', abortHandler, false);
ajax.open('POST', route);
ajax.send(formData);
}
The functions in the event listeners have code to take appropriate actions like displaying a progress bar..Thanks in advance for the help
The issue you are having based off the error message 'Failed to complete operation due to low memory' is that you are specifically running out of RAM (or allotted RAM for that application/instance on mobile).
Uploading Techniques in Javascript
you see the issue with upload the 30MB file is that it needs to load the entire file into memory, I'm not sure about the exact details of who owns those memory addresses weather it be application restriction so Chrome or the device itself. Your best bet is to do chunk uploading, It has many benefits and will now allow you to only have to take up 1MB (or whatever size you want) to be chunked at. This allows the upload to be smoother as it no longer needs to have the entire video loaded.
It's a pretty big article/solution so I wont be adding code into the answer since there are many pieces to it, but I have used that as a base to implement the chunking uploading. This will solve your issue on all browsers/devices.
-- as a side note you could always limit how much is uploaded so this doesn't occur but if big uploads is what you are trying to achieve this is a good point to start.
I am using Chrome. In my dev tools console, I tried the following:
Everything works as expected except last line. Why can't I set currentTime on it?
Also in general, I am finding this whole HTML5 Audio thing to not be very reliable. Is there a robust javascript wrapper that fallsback to flash ?
You need to do something like this (if you use jQuery)
$('#elem_audio').bind('canplay', function() {
this.currentTime = 10;
});
or in Javascript
var aud = document.getElementById("elem_audio");
aud.oncanplay = function() {
aud.currentTime = 10;
};
The reason behind for this setup is you need to make sure the audio is ready to play.
Check your HTTP server configuration, in my testing environment ( Chrome 69 on Mac OS) setting currentTime property of audio element works only when the audio source is served by a HTTP server support persistent connection.
If the HTTP server you used support persistent connection, you will found (in Chrome DevTool) the Connection field of response headers of your audio source be keep-alive. By contrast if the audio source is served by a persistent connection incompatible server, there will be no Connection field in response headers.
The status code of your audio source HTTP request will be a reference too, 206 Partial Content for persistent connection supported server, 200 OK for an inferior one.
I had the same problem, and the reason was missing headers on the mp3 file, like:
Content-Length, Content-Range, Content-Type
Why cant I set currentTime on it?
Could not reproduce currentTime being set to 0 after setting to 10. Is 18.mp3 duration less than 10?
var request = new XMLHttpRequest();
request.open("GET", "/assets/audio/18.mp3", true);
request.responseType = "blob";
request.onload = function() {
if (this.status == 200) {
var audio = new Audio(URL.createObjectURL(this.response));
audio.load();
audio.currentTime = 10;
audio.play();
}
}
request.send();
jsfiddle http://jsfiddle.net/Lg5L4qso/3/
I ran into this problem after I'd started to use the PHP Server extension to VS Code to serve my HTML/PHP local testing. The problem was resolved for me by going back to my old Abysswebserver setup.
So, it's not simply that "you can't manipulate .currentTime on locally served files" but rather that "you need to pick a server that gives you the right headers". The Status entry for my file from AbyssWebserver, for example, read "Status Code: 206 Partial Content" while the one from PHP Server read "Status Code: 200 OK".
There are other differences though so there may be more to this than just the Status entry. See https://github.com/brapifra/vscode-phpserver/issues/85, for a full header comparison.
If you want to return to the beginning of the audio after it has been played, use load().
// x.currentTime = 0;
x.load();
( https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/load )
this worked for me:
var callaudio = audio; // the audio variable
function fetchAudioFile() {
var requestObj = new Request(callaudio.src, {
method: 'GET',
headers: {
'Accept-Ranges': '1000000000'
},
referrerPolicy: 'no-referrer'
});
fetch(requestObj).then(function (response) {
returnresponse;
}).then(async function (outcome) {
const blob = await outcome.blob();
const url = window.URL.createObjectURL(blob);
callaudio.src = url;
});
};
fetchAudioFile();
The only solution for setting currentTime I got to work reliably was using the onprogress event.
audio.onprogress = function() {
if (audio.currentTime == 0) {
audio.currentTime = 10;
}
}
The solution which worked for me was not setting "src" on directly, but use with type attribute, maybe type attribute is helping browser some way.
My guess is that '10' is longer that you mp3's length.
But that logs the length of mp3 instead of '0'.
I'm working on an uploader for angular-js that can give me progress updates. The code below works however on chrome, for files that are under around 3MB, one progress update fires before it starts sending, and the event data indicates that all the bytes are uploaded. It then takes some time (up to 30secs) before the file data is actually sent (and no further progress events will fire during the actual upload). If I use a larger file, I'll get two events or maybe three. On firefox, I'll get around 6 progress events for a 2MB file. Does anyone know if there's a way to adjust the granularity of these updates to fix this. To me, this function is basically useless (on chrome) since most documents aren't that big. Thanks.
send: function() {
var document = {
DocumentName: this.fsEntry.file.name
};
var formdata = new FormData();
formdata.append('file', this.fsEntry.file);
formdata.append('metadata', JSON.stringify(document));
this.xhr = new XMLHttpRequest();
this.xhr.addEventListener("loadstart", this.onLoadStart, false);
this.xhr.upload.addEventListener("progress", this.onProgress, false);
this.xhr.addEventListener("load", this.onComplete, false);
this.xhr.open("POST", this.fsEntry.uploadUri, true);
this.xhr.send(formdata);
}
this.onProgress = function(e) {
if (e.lengthComputable) {
console.log("progress: uploaded " + e.loaded + " of " + e.total);
}
}
Is it possible to get the progress of an XMLHttpRequest (bytes uploaded, bytes downloaded)?
This would be useful to show a progress bar when the user is uploading a large file. The standard API doesn't seem to support it, but maybe there's some non-standard extension in any of the browsers out there? It seems like a pretty obvious feature to have after all, since the client knows how many bytes were uploaded/downloaded.
note: I'm aware of the "poll the server for progress" alternative (it's what I'm doing right now). the main problem with this (other than the complicated server-side code) is that typically, while uploading a big file, the user's connection is completely hosed, because most ISPs offer poor upstream. So making extra requests is not as responsive as I'd hoped. I was hoping there'd be a way (maybe non-standard) to get this information, which the browser has at all times.
For the bytes uploaded it is quite easy. Just monitor the xhr.upload.onprogress event. The browser knows the size of the files it has to upload and the size of the uploaded data, so it can provide the progress info.
For the bytes downloaded (when getting the info with xhr.responseText), it is a little bit more difficult, because the browser doesn't know how many bytes will be sent in the server request. The only thing that the browser knows in this case is the size of the bytes it is receiving.
There is a solution for this, it's sufficient to set a Content-Length header on the server script, in order to get the total size of the bytes the browser is going to receive.
For more go to https://developer.mozilla.org/en/Using_XMLHttpRequest .
Example:
My server script reads a zip file (it takes 5 seconds):
$filesize=filesize('test.zip');
header("Content-Length: " . $filesize); // set header length
// if the headers is not set then the evt.loaded will be 0
readfile('test.zip');
exit 0;
Now I can monitor the download process of the server script, because I know it's total length:
function updateProgress(evt)
{
if (evt.lengthComputable)
{ // evt.loaded the bytes the browser received
// evt.total the total bytes set by the header
// jQuery UI progress bar to show the progress on screen
var percentComplete = (evt.loaded / evt.total) * 100;
$('#progressbar').progressbar( "option", "value", percentComplete );
}
}
function sendreq(evt)
{
var req = new XMLHttpRequest();
$('#progressbar').progressbar();
req.onprogress = updateProgress;
req.open('GET', 'test.php', true);
req.onreadystatechange = function (aEvt) {
if (req.readyState == 4)
{
//run any callback here
}
};
req.send();
}
Firefox supports XHR download progress events.
EDIT 2021-07-08 10:30 PDT
The above link is dead. Doing a search on the Mozilla WebDev site turned up the following link:
https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent
It describes how to use the progress event with XMLHttpRequest and provides an example. I've included the example below:
var progressBar = document.getElementById("p"),
client = new XMLHttpRequest()
client.open("GET", "magical-unicorns")
client.onprogress = function(pe) {
if(pe.lengthComputable) {
progressBar.max = pe.total
progressBar.value = pe.loaded
}
}
client.onloadend = function(pe) {
progressBar.value = pe.loaded
}
client.send()
I also found this link as well which is what I think the original link pointed to.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/progress_event
One of the most promising approaches seems to be opening a second communication channel back to the server to ask it how much of the transfer has been completed.
For the total uploaded there doesn't seem to be a way to handle that, but there's something similar to what you want for download. Once readyState is 3, you can periodically query responseText to get all the content downloaded so far as a String (this doesn't work in IE), up until all of it is available at which point it will transition to readyState 4. The total bytes downloaded at any given time will be equal to the total bytes in the string stored in responseText.
For a all or nothing approach to the upload question, since you have to pass a string for upload (and it's possible to determine the total bytes of that) the total bytes sent for readyState 0 and 1 will be 0, and the total for readyState 2 will be the total bytes in the string you passed in. The total bytes both sent and received in readyState 3 and 4 will be the sum of the bytes in the original string plus the total bytes in responseText.
<!DOCTYPE html>
<html>
<body>
<p id="demo">result</p>
<button type="button" onclick="get_post_ajax();">Change Content</button>
<script type="text/javascript">
function update_progress(e)
{
if (e.lengthComputable)
{
var percentage = Math.round((e.loaded/e.total)*100);
console.log("percent " + percentage + '%' );
}
else
{
console.log("Unable to compute progress information since the total size is unknown");
}
}
function transfer_complete(e){console.log("The transfer is complete.");}
function transfer_failed(e){console.log("An error occurred while transferring the file.");}
function transfer_canceled(e){console.log("The transfer has been canceled by the user.");}
function get_post_ajax()
{
var xhttp;
if (window.XMLHttpRequest){xhttp = new XMLHttpRequest();}//code for modern browsers}
else{xhttp = new ActiveXObject("Microsoft.XMLHTTP");}// code for IE6, IE5
xhttp.onprogress = update_progress;
xhttp.addEventListener("load", transfer_complete, false);
xhttp.addEventListener("error", transfer_failed, false);
xhttp.addEventListener("abort", transfer_canceled, false);
xhttp.onreadystatechange = function()
{
if (xhttp.readyState == 4 && xhttp.status == 200)
{
document.getElementById("demo").innerHTML = xhttp.responseText;
}
};
xhttp.open("GET", "http://it-tu.com/ajax_test.php", true);
xhttp.send();
}
</script>
</body>
</html>
If you have access to your apache install and trust third-party code, you can use the apache upload progress module (if you use apache; there's also a nginx upload progress module).
Otherwise, you'd have to write a script that you can hit out of band to request the status of the file (checking the filesize of the tmp file for instance).
There's some work going on in firefox 3 I believe to add upload progress support to the browser, but that's not going to get into all the browsers and be widely adopted for a while (more's the pity).
The only way to do that with pure javascript is to implement some kind of polling mechanism.
You will need to send ajax requests at fixed intervals (each 5 seconds for example) to get the number of bytes received by the server.
A more efficient way would be to use flash. The flex component FileReference dispatchs periodically a 'progress' event holding the number of bytes already uploaded.
If you need to stick with javascript, bridges are available between actionscript and javascript.
The good news is that this work has been already done for you :)
swfupload
This library allows to register a javascript handler on the flash progress event.
This solution has the hudge advantage of not requiring aditionnal resources on the server side.