JavaScript img.src onerror event - get reason of error - javascript

There can be different reasons for <img> load errors, such as network error response, bad image data...
error object received from onerror doesn't seems to specify the exact reason.
Is there a way to know if the error is because of a network error, say HTTP 500 or a network timeout?
EDIT:
I'm not looking for an alternative way to load a resource, such as AJAX request. I need an answer specifically for <img> tag with onerror event. The reason for that is that I'm using this method for pixel-tracking and I need a way to retry on upon network errors. I'm also not looking for alternative tracking methods such as JSONP.

Edit 16Nov16 2020GMT
Maybe you are pixel-tracking in emails or other clients limited in Javascript capabilities.
One idea that comes to mind is to use URL query paramters in your <img>'s src URL.
With regards to network timeouts, I will pose the idea that a user opens an email, loads the email entirely, then disconnects from the internet and somehow this does not give the tracker enough time to load.
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
I would suggest to use setTimeout() inside your onerror function.
This will continue attempting to set/load the <img>'s src URL. You could append the seconds it took until successful load to the URL of your src file as a query parameter like ?s=<sec>
As far as determining status 500 codes on image loads you might want to consider creating a custom 500 error file which would then create -- for example -- a MySQL database entry with all sorts of information you have access to and if you chose to use the query parameters mentioned before then you have slightly more information added to the error.
onerror for <img> gives limited information about the network
The information that is available from <img> can be found at
https://www.w3.org/TR/html/semantics-embedded-content.html#htmlimageelement-htmlimageelement
Older answer:
Perhaps a route you would like to try is to use AJAX to load the image data and set the <img> src to the base64 of the image data received. I hope this helps.
Edit 14Nov16 2018GMT
Alternatively use AJAX to determine if the image loads properly and then use the same URL sent to AJAX as the src for your <img>. It would of course be redundant but would avoid the issue of long "data" URLs.
Edit 15Nov16 0832GMT
Also regarding Network Timeout I found this thread to be useful JQuery Ajax - How to Detect Network Connection error when making Ajax call
Apparently you can specify a timeout to AJAX much like using error except you just provide the miliseconds manually.
Converting to Base64
https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
var encodedData = window.btoa("Hello, world"); // encode a string
Or if you are concerened about older browsers able to use btoa() then you might be interested in Google's https://chromium.googlesource.com/chromiumos/platform/spigots/+/refs/heads/firmware-u-boot-v1/base64_encode.js
Status Code checks in jQuery's AJAX
jQuery: How to get the HTTP status code from within the $.ajax.error method?
$.ajax({
type: 'GET',
url: '/path-to-my/image.png',
data: null,
success: function(data){
alert('horray! 200 status code!');
// convert to base64; add to img.src # btoa(data)
document.querySelector("#hlogo img").src = "data:;base64,"+ data;
},
error:function (xhr, ajaxOptions, thrownError){
switch (xhr.status) {
case 400:
// Take action, referencing xhr.responseText as needed.
case 404:
// Take action, referencing xhr.responseText as needed.
case 500:
// Take action, referencing xhr.responseText as needed.
}
});
Notes
https://www.rfc-editor.org/rfc/rfc2397#section-3
dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
mediatype := [ type "/" subtype ] *( ";" parameter )
data := *urlchar
parameter := attribute "=" value
https://www.rfc-editor.org/rfc/rfc2046#section-4.2
Using of a generic-purpose image viewing application this way
inherits the security problems of the most dangerous type supported
by the application.
https://www.rfc-editor.org/rfc/rfc2397#page-4
The effect of using long "data" URLs in applications is currently
unknown; some software packages may exhibit unreasonable behavior
when confronted with data that exceeds its allocated buffer size.
Other References
Unknown file type MIME?
Asynchronously load images with jQuery

Related

PNG Data Url damaged after sending it with Ajax

I wanted to send a PNG Data Url with Ajax to my PHP-Script but the Url on the Client Side is not the same that i recive with PHP.
$.ajax({
url: "proceed.php",
type: "post",
data: "signature=" + signaturePad.toDataURL('image/png'),
error: function(e) {
alert("ERROR");
console.log(e);
},
success: function(e) {
alert(e);
}
});
I think it gets damaged while sending - maybe a encoding problem?
I Already tried to encode the URL with JSON but it's the same problem...
data: "singature=" + JSON.stringify(signaturePad.toDataURL("image/png")
I presume you are using HTML5's canvas.toDataUrl() as described here.
Your image data is not the same, because instead of sending the actual image, you are sending the data of the image that is painted on your site.
As the browser is throwing away unneeded data and (probably) keeping only RGBA and size information, the image you receive is understandably 'mangled'. Documentation also states that the image resolution will always be only 96 dpi.
There could also be problems arising from using URI component for transfer of "binary data" (these quotes are supposed to be huge). There seems to be no set lower or upper bound for URI component, as stated here. I would suggest using this technique only in case of small (IMHO around 40x40px) images.
Refer here on how to send bigger images over jQuery's $.ajax().

download file and then leave page

$http.post('#Url.Action("donePressed")',
{
id: $scope.id,
}).then(
function (response) // success callback
{
window.location = '#Url.Action("PdfCreator", "someController")?Id=' + $scope.id;
window.location='#Url.Action("Index","AnotherController")';
},
function (response) // failure callback
{
alert(response.statusText);
});
Hi, I guess I am doing somehting wrong, I want to call to a function the sends me a file as a response, and afterwords I want to leave the page and go somewhere else.
the problem is, because this is a sync I don't get my download.
How can I make this synced?
Async has nothing to do with it. Once you're inside the success callback, the async part is already done. The problem is that you're changing the window location again before the first change has had time to load. In other words, it's the exact opposite of an async problem; the problem is that this code is synchronous and runs too fast.
However, the approach here is flawed to begin with. It might work if the browser was forced to download the file, as the then the first change to window.location would not itself cause the browser view to change. Since PDF is typically a browser-viewable type, this is not guaranteed, though. Regardless, you still have the same issue of need to delay the second call until the first has gotten a response, which is basically impossible. There's no built in event for this type of thing, so the best you'd could do would be to is use setTimeout with a 1-2 second delay, and just hope that that is enough time to get the first response. Even then, if it ever took longer, your code would break again. In other words, it's going to be extremely brittle.
The simple fact is that this is just simply not how HTTP works. You're basically trying to return two responses for a single request, which is not possible. This is a clever way to try to skirt around inherent restrictions in the protocol, I'll give you that, but it's ultimately still insufficient.
All that said, you can actually make this happen via the HTML5 File API and AJAX, but your solution then will only be compatible with modern browsers (basically everything except IE 10 and under). If you do not need to support lesser versions of IE, then you can use the following code instead:
function (response) // success callback
{
$http.get('#Url.Action("PdfCreator", "someController")?Id=' + $scope.id').then(
function (response) // success callback
{
var a = document.createElement('a');
var url = window.URL.createObjectURL(response.data);
a.href = url;
a.download = 'myfile.pdf';
a.click();
window.URL.revokeObjectURL(url);
window.location = '#Url.Action("Index","AnotherController")';
},
function (response) // failure callback
{
alert(response.statusText);
}
);
},
The secret sauce is in fetching the PDF via AJAX and then creating an object URL out of the PDF data. You can then use that to create an anchor element in the DOM and "click" it dynamically to prompt the download. The caveat, though, is that I haven't tried to do this with Angular, so I'm unsure if $http supports getting a binary response. I know with jQuery, you just have to tell it that the XHR object's response type is 'blob', but I'm not sure if you can or how you would do the same thing with Angular. As an alternative, you can simply use XMLHttpRequest directly for this particular AJAX, and simply set xhr.responseType = 'blob'.

Cannot carry out Ajax request from wikipedia

I want to use wikipedia API in my project to grab images of people, but fail. I use this url:https://en.wikipedia.org/w/api.php?action=query&prop=pageimages&titles=Albert%20Einstein&pithumbsize=100
When i console browser says the following
Refused to execute script from 'https://en.wikipedia.org/w/api.php?action=query&prop=pageimages&titles=Albe…Callback&callback=jQuery22409288979864744966_1470068280411&_=1470068280412' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
My code
var general = {
// The URL to the quote API
url: 'http://api.forismatic.com/api/1.0/',
// What to display as the author name if s/he's unknown
unknownAuthor: 'Uknown',
// Base URL for the tweet links generation
tweetURL: 'http://twitter.com/home?status=',
wikiURL:'https://en.wikipedia.org/w/api.php?action=query&prop=pageimages&titles=Albert Einstein&pithumbsize=100&callback=wikiCallback'
};
var wikirequest = function() {
$.ajax({
url:general.wikiURL,
dataType: 'jsonp',
success: function(wikData) {
console.log(wikData);
//var image = wikiData.
displayQuote(image);
} // end of success
});
}// wikirequest
wikirequest();
Pen
Has anyone met the same issue?
You are trying to load the data using JSONP, but you are making a request to a URL that returns an HTML document. JSONP requests have to be answered with JavaScript programs (since that is a fundamental feature of how they work … and also why they are dangerous and should be avoided in favour of plain JSON and CORS).
To make it return JSONP you need to provided two additional query string parameters:
format=json
callback=YourCallbackName
… where YourCallbackName is the name of the function that should be executed and passed the data you are fetching as an argument. Most Ajax libraries will generate that name (and the function itself) dynamically when you specify callback=?.
https://en.wikipedia.org/w/api.php?action=query&prop=pageimages&titles=Albert%20Einstein&pithumbsize=100&format=json
You are missing the &format=json on the URL - The page was displaying the data with the html header and you would have been attempting to decode this. The above answer is actually better.

JSON.parse causes Chrome tab to crash ("Aw, Snap") despite use of try/catch

I'm loading some JSON data from an AJAX query:
$.ajax({'url': url, type: params.method, 'data': data, timeout: this.settings.timeout, success: function(d,a,x){
console.log('request Complete',params.endpoint,params.params);
var json = null;
try {
json = JSON.parse(d);
} catch(e) {
console.error(e);
}
console.log('json');
// omitted for brevity...
}
});
I'm seeing occasional "Aw, Snap" crashes in chrome where the last console.log is the "request Complete" (the error or 2nd log never get shown).
I suppose that it's important to note that the data may be large (sometimes as big as ~15Mb), which is why I'm not printing out d on every request and looking for malformed JSON (yet... I may result to that). FWIW, I've also tried $.parseJSON instead of JSON.parse
Research I've done into the "Aw, Snap" error is vague, at best. My best guess atm is that this is an OOM. Unfortunately, there's not much I can do to decrease the footprint of the result-set.
Is there any way I could, at the least, gracefully fail?
What happens when you tell jQuery the response data is JSON via the dataType property? Doing so should cause jQuery to pre parse and just give you the data. If you're right about what is going on, it seems this might cause a crash too. jQuery does some sanity checks before parsing, though.
$.ajax({
url: url,
type: params.method,
data: data,
dataType: 'json',
timeout: this.settings.timeout,
success: function (d, a, x){
// `d` should already be parsed into an object or array, and ready to use
}
});
If that doesn't help, please post your actual JSON response for us to take a look at.
"#the system" nailed it. 15MB of info coming back is too much for your browser to handle. I tripped upon this trying to see why my 64 Byte encoded image string is crashing the chrome tab, and it's only 200-500KB.
To 'gracefully fail', it seems you will need to have server side logic in place to prevent this from happening; perhaps limit the size of the JSON string. Only have X characters of length in the initial JSON string and add a property for 'isFinishedSending: false' or 'leftOff: [index/some marker]' so you can timeout for a bit and hit your server again with the the place you left off.

JQuery external Ajax call not working in IE

I have an ajax script that sends some data to an external URL. The external URL is hosted on the same server, however the domain is different than the source of the ajax call.
This is working perfectly in Firefox and Chrome. However in IE The ajax call does not go through, and the Return False function does not either work (once the ajax call fails).
Below is my code:
$.get('http://myexternaldomian.com/feedback/save.php', {
answer: $('#answer').val(),
page_url: pathname
});
// Keeps the user on the page
return false;
When I try removing the http:// from the ajax url, the return false does work.
Any help on this would be greatly appreciated. Thank You
From jQuery documentation
Due to browser security restrictions,
most "Ajax" requests are subject to
the same origin policy; the request
can not successfully retrieve data
from a different domain, subdomain, or
protocol.
and Same Origin Policy on Wiki
I'm surprised any of them are working. Browsers generally don't allow ajax calls to a domain other than the one the current page came from.
The main exception to this rule is if you make an ajax call using jsonp (json with padding). You can do this with jQuery, here's how. Look under the dataType option.
(this is copypaste from my another similar answer). You could try enabling "jQuery.support.cors=true" flag and see how it goes. I use jQuery v1.7.2.
I had to load webpage from local disk "file:///C:/test/htmlpage.html", call "http://localhost/getxml.php" url, and do this in IE8+ and Firefox12+ browsers, use jQuery v1.7.2 lib to minimize boilerplate code. After reading dozens of articles finally figured it out. Here is my summary.
server script (.php, .jsp, ...) must return http response header Access-Control-Allow-Origin: *
before using jQuery ajax set this flag in javascript: jQuery.support.cors = true;
you may set flag once or everytime before using jQuery ajax function
now I can read .xml document in IE and Firefox. Other browsers I did not test.
response document can be plain/text, xml, json or anything else
Here is an example jQuery ajax call with some debug sysouts.
jQuery.support.cors = true;
$.ajax({
url: "http://localhost/getxml.php",
data: { "id":"doc1", "rows":"100" },
type: "GET",
timeout: 30000,
dataType: "text", // "xml", "json"
success: function(data) {
// show text reply as-is (debug)
alert(data);
// show xml field values (debug)
//alert( $(data).find("title").text() );
// loop JSON array (debug)
//var str="";
//$.each(data.items, function(i,item) {
// str += item.title + "\n";
//});
//alert(str);
},
error: function(jqXHR, textStatus, ex) {
alert(textStatus + "," + ex + "," + jqXHR.responseText);
}
});
http://en.wikipedia.org/wiki/Same_origin_policy
I dont think it should work on Chrome or Firefox, unless you testing on localhost or something like that, this would be against the crossdomain policy.
What you need is to proxy it inside the same domain, use php to connect to the destination you need and call the url from the same domain.
save_cross_domain.php -> connect through server to the desired url
then ajax calls save_cross_domain.php
you should add a
callback=?
to your url and handle this on the server side.
I did this once for a java servlet, and when the callback param was included I added an extra pair of parenteses around the json response..
hope it helps!
A couple of things:
The answers/conversation for this question has gone a bit out of context. Actually from the question it was more implied how to make ajax calls in IE. [Atleast modify the question title, else the question is very localized]
A couple of solutions to this cross-domain issue:
CORS[compatible after IE7]
JSONP [ here actually the browser takes in the input thinking it is a script]
server side encoding

Categories

Resources