I'm trying to run "inherited" code and since I'm fairly new to HTML & javascript I keep running into annoying little issues (that's how you learn :D ).
I have a GET request that is meant to load an mp4 file from a server, but for the sake of debugging and practice, I'm trying to load it from a local directory. I enabled the "--allow-file-access-from-files" flag on my chrome, so I know it's not a SOP issue. I can't figure out why, the request is sent 3 times, ALWAYS the first and last fail and the 2nd doesn't, but the file is not loaded.
here's a simplified version of the code:
var req = new XMLHttpRequest();
req.open('GET', currentFileName, true);
// currentFileName is an mp4 in the same directory
req.responseType = 'blob';
req.onload = function () {
// Onload is triggered even on 404
// so we need to check the status code
if (this.status === 200) {
console.log("success!");
doSomeFunc();
}
}
};
req.send();
here's the network log:
I looked into many possible solutions (example 1, 2, 3, 4, 5)
Couldn't find a question where this happens with local files.
What might be wrong?
Related
I tested the loading of very large files with XMLHttpRequest and noticed an interesting behavior of Chrome (90.0.4430.212): It loads the full file, but finishes with a 200-OK code and and empty (!) result. First I thought it was a silent timeout or whatever, but no, it seems to be a reached memory limit.
Trying it in Firefox (13.0esr (64-bit)) took for ages, but in the end I knew more: The Transfer itself did not trigger an "error" or a "timeout" event, resulted with 200 and empty result as well. But it threw an error:
Exception { name: "NS_ERROR_OUT_OF_MEMORY", message: "", result: 2147942414, filename: "http://localhost/testcenter-backend/vo_data/teterei.html", lineNumber: 16, columnNumber: 0, data: null, stack: "transferComplete#http://localhost/testcenter-backend/vo_data/teterei.html:16:9\n" }
So it has nothing to do with the transport itself, but apparently a memory limit reached when trying to do anything with the result. When I don't use the oReq.response, the error does not appear.
Okay, how to handle this? In Firefox I can catch the error with a simple try catch block. But this does not work for Chrome. A naive approach would be just to check if the resulting content is empty, but I wonder if there is another possibility to detect this stuff happening.
--
How to reproduce:
Create a huge file.
I generated a 10,4GB file this way:
dd if=/dev/zero of=test.img bs=1024 count=0 seek=$[1024*10000]
Run this code in a browser to load it.
const oReq = new XMLHttpRequest();
function updateProgress (oEvent) {
console.log("progress", oEvent.loaded);
}
function transferComplete(evt) {
console.log("The transfer is complete.", oReq.getAllResponseHeaders(), oReq.status);
console.log(oReq.response); // here too much memory is allocated
}
function transferFailed(evt) {
console.log("error", oReq.getAllResponseHeaders(), oReq.status);
}
function transferCanceled(evt) {
console.log("cancel", oReq.getAllResponseHeaders(), oReq.status);
}
function timeOut(evt) {
console.log("timeout", oReq.getAllResponseHeaders(), oReq.status);
}
oReq.addEventListener("progress", updateProgress);
oReq.addEventListener("load", transferComplete);
oReq.addEventListener("error", transferFailed);
oReq.addEventListener("abort", transferCanceled);
oReq.addEventListener("timeout", timeOut);
// your huge file here instead
oReq.open("GET", "https://cdn.jsdelivr.net/npm/jquery#3.2.1/dist/jquery.min.js"); // URL to huge file here
oReq.send();
The actual memory limit may vary to your system.
I have a very simple function that downloads chunks of a file using an xhr request that looks like so:
var blobXHR = new XMLHttpRequest();
//api.media.chunkURL() returns the correct URL for each chunk
blobXHR.open("GET", api.media.chunkURL({
fileId: fileID,
chunkId: chunkNumber
}));
blobXHR.responseType = "arraybuffer";
blobXHR.onerror = function (e) {
console.log("Error: ", e);
};
var arrayBuffer;
blobXHR.onload = function (e) {
arrayBuffer = blobXHR.response;
};
blobXHR.send();
Now this download function works without any hitches at all using Chrome, Firefox, and just about every Android browser. Unfortunately, when using anything Safari or iOS based I get a very vague error in blobXHR.onerror(). When I output this error to the console I get this response under "e.currentTarget.responseText":
Error: InvalidStateError: DOM Exception 11
I've looked up many questions similar to this and nothing has seemed to work. Any reason why I would be experiencing this with only Safari/iOS browsers?
Edit: This is what I get when I console.log(blobXHR) within onerror():
This is likely a CORS issue. Make sure your server is properly configured to allow this:
http://enable-cors.org/server.html
Also be mindful that Safari won't allow localhost for CORS.
I have a web project in PHP and it accesses a Java Project that uses the Restlet Framework. The web project is running on Apache and I am testing it using localhost. The Restlet Framework also uses localhost as the domain, but the url is slightly different: localhost:8888/
This is the Javascript that, using Ajax, makes a call to one of the Java classes (CollectionPublic) using the URL above.
var url = "<?php echo $config['restServer_url'] ?>collectionPublic";
var params= "pageList="+facebookPages+"&time="+time;
var client = new XMLHttpRequest();
client.open("POST", url,true);
client.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
client.onreadystatechange = function () {
if (client.readyState != 4) return;
if (client.status != 200 && client.status != 304) {
alert("error "+client.status);
} else {
alert("success");
}
callback(client);
}
if (client.readyState == 4) return;
client.send(params);
I have tested and the call is being made correctly, using the URL localhost:8888/collectionPublic, and it is reaching the CollectionPublic class (the class is working fine).
The PROBLEM is: When this call is made, the CollectionPublic class takes a long time to complete its task, and the user should be able to access other pages (on the same server) or reload the page. However, when either of these things happen, the alert("error "+client.status) pops up and the value of client.status is 0. The call is then aborted, but the CollectionPublic's task continue normally, and when it finishes, nothing happens in the web page (before, the alert("success") was being fired).
I spent hours trying to figure out what was causing the error, since this was working last week. Most of the posts I found said that it could be a Cross-Origin Resource problem, since localhost and localhost:8888 are not considered as the same domain. To see if that was really the problem, I started Chrome using the --disable-web-security argument (and it was really disabled) but the issue was still there.
The weirdest thing is that it has worked before, and I changed absolutely NOTHING in the code.
I have seen this post Reloading page while an Ajax request in progress gives empty response and status as zero and it seems quite similar to what I am facing.
Hopefully, I have made myself clear, but if you have any doubts regarding this issue, just ask.
Thanks a lot in advance.
I'm not convinced that the ajax request itself is quite right. if (client.readyState != 4) return; will always be true aside from when its actually 4. This may be better:
client.onreadystatechange = function () {
if(client.readyState < 4) {
//not complete yet
return;
}
if(client.status != 200 && client.status != 304) {
//an error
alert("error "+client.status);
return;
}
if(client.readyState === 4) {
//complete
callback(client);
}
}
As for the problem whereby the ajax call is aborted: This is correct behaviour. All XHR calls will be aborted by the browser as soon the page is reloaded or unloaded. Perhaps this was somehow not the case when viewing pages locally. I would not allow the user to navigate away (or reload) whilst the ajax in progress. As a work-around, your class could set a session variable that is read by your page.
I come here hoping that you lovely folks here on SO can help me out with a bit of a problem that I'm having.
Specifically, every time I attempt to use the decodeAudioData method of a webkitAudioContext, it always triggers the error handler with a null error. This is the code that I'm currently using:
var soundArray;
var context = new webkitAudioContext();
function loadSound(soundName) {
var request = new XMLHttpRequest();
request.open('GET',soundName);
request.responseType = 'arraybuffer';
request.onload = function() {
context.decodeAudioData(this.response, function(buf) {
sounds[soundName] = buf;
},function(err) { console.log("err(decodeAudioData): "+err); });
}
request.send();
}
At this point, it constantly logs error messages to the console saying err(decodeAudioData) = null, mostly because that was just how I decided to log it.
In any case, any idea why this might be going on?
I'm using Chrome Canary, v20.0.1121.0, to try and get something working. But, obviously, it's not working! So, any idea what I might be able to do? If any new information is needed, let me know, and I'll update as necessary.
The real reason is that both createBuffer and decodeAudioData right now have a Bug and throw weird vague DOM exception 12 for files they should normally play.
But we should be aware that this is new and evolving technology and be thankful even for web audio api as it is now since its small miracle that happened to us.
They are missing stream syncing on header boundary that any reasonable decoder of streaming audio format should start with.
And mp3 or many aac/adts files are streaming fileformats. streaming means that you can cut them anywhere or insert append anything (various tags even image artwork) decoder shouldnt care about unknown data. decoder should just seek until he finds header he knows and can decode.
I thrown together this temporary solution that seeks to nearest frame header start and passes data from this offset only.
mp3 or mp2 all start header for every audio frame (every around 200bytes) with 0XFFE and aac(adts) on oxFFF syncword that is there just for this reason. therefore both will sync on 0xFFE.
Here is the code I currently use to play previously not played files.
What I hate is that arrayBuffer doesnt have subarray() like its typed childs to return just different view from different offset instead of whole new array copy that slice() returns. if only webaudio api accepted typedarrays as input but unfortunately the only way to create arraybuffer back seems huge slice() copy.
thankfully usually only one or two seeks are needed.
Forcing Web Audio Api to not being Picky about files
node={};
node.url='usual_mp3_with_tags_or_album_artwork.mp3';
function syncStream(node){ // should be done by api itself. and hopefully will.
var buf8 = new Uint8Array(node.buf);
buf8.indexOf = Array.prototype.indexOf;
var i=node.sync, b=buf8;
while(1) {
node.retry++;
i=b.indexOf(0xFF,i); if(i==-1 || (b[i+1] & 0xE0 == 0xE0 )) break;
i++;
}
if(i!=-1) {
var tmp=node.buf.slice(i); //carefull there it returns copy
delete(node.buf); node.buf=null;
node.buf=tmp;
node.sync=i;
return true;
}
return false;
}
function decode(node) {
try{
context.decodeAudioData(node.buf,
function(decoded){
node.source = context.createBufferSource();
node.source.connect(context.destination);
node.source.buffer=decoded;
node.source.noteOn(0);
},
function(){ // only on error attempt to sync on frame boundary
if(syncStream(node)) decode(node);
});
} catch(e) {
log('decode exception',e.message);
}
}
function playSound(node) {
node.xhr = new XMLHttpRequest();
node.xhr.onload=function(){
node.buf=node.xhr.response;
node.sync=0;
node.retry=0;
decode(node);
}
node.xhr.open("GET", node.url, true);
node.xhr.responseType = "arraybuffer";
node.xhr.send();
}
I was using webkitAudioContext with Chrome 19. Today I've upgraded to Chrome 20 and I have the same problem as you.
I have taken another MP3 file and it works again. The only difference between the two files is the cover embedded in the wrong MP3 file.
I have removed the cover and it works again.
My application uses polling to update the status of a music player. I'm using setInterval to make an Ajax call every half a second to do this. It works on many browsers (Chrome,Firefox, Safari... ) except the Nook color's browser. When the page loads it updates the correct information, but after that it always loads the same information. This was confirmed using alert. Here's the original code
function getStatus() {
request = new XMLHttpRequest();
request.open("GET", SOME_URL, true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200)
updateStatus(request.responseText);
};
request.send()
}
setInterval(getStatus, 500);
Any ideas why it is always loading the same info (the info it fetches initially) ?
Also: it only loads the most current information if you clear the cache. This Nook was rooted and also had Firefox and it would work just fine. It's the Nook native browser that is doing this (rooted or unrooted).
Internet Explorer has a weird quirk where it caches AJAX content. I imagine you are seeing the same issue in the Nook browser. The solution is to add a "cache buster" parameter, which is basically just a random parameter so the URL is treated freshly:
"SOME_URL?random=" + Math.random()