Identify fetch error as due to CORS issue - javascript

I'd like to tell if a resource load has failed due to a CORS error, as I'd like to then use a proxy I've set up on my server. I don't want to use my proxy unless absolutely necessary as quite a lot of extra data will be piped through it.
When I do:
fetch("https://some-resource-somewhere-that-a-user-has-provided")
.then(response => {
// do stuff with the response
}).catch((e) => {
// e === Error("TypeError: Failed to fetch")
});
The error is pretty unhelpful (on chrome at least), but there is big red text in the console giving me the information I need!
How do I tell that
TypeError: Failed to fetch
is a CORS issue, or some other load problem?

I came up with below solution:
var xhttp = new XMLHttpRequest();
xhttp.onerror = function () {
if (this.status === undefined || this.status === 0) {
console.log('error due to CORS issue');
} else {
console.log("** An error occurred during the transaction", this);
}
};
xhttp.open("GET", "https://stackoverflow.com", true);
xhttp.send();

Related

Youtube API v3 get the Channel ID of user that uploaded a certain video

I want to get the channel ID of a user that uploaded a certain YouTube video on javascript to after that comparing the channel id to see if it's in an array.
The thing is, I can't find exactly how to get that from javascript. I tried to get:
https://www.googleapis.com/youtube/v3/videos?part=snippet&id=[Video ID]&key=[my key]
but it gives me JSON parsing error on every video.
Anyone knows how to do it exactly using YouTube API? Doesn't matter if I have to add an exteral script on the html part.
And, as an example of what I want to do, for this video:
https://www.youtube.com/watch?v=jNQXAC9IVRw
it should return 'UC4QobU6STFB0P71PMvOGN5A'.
Any idea on how to do it?
I took the Ajax code from youmightnotneedjquery.com and edited it a bit to make a getJSON utility function. This worked for me:
var API_KEY = 'YOUR_API_KEY'; // Replace this with your own key
getJSON(
'https://www.googleapis.com/youtube/v3/videos?part=snippet&id=jNQXAC9IVRw&key=' + API_KEY,
function (err, data) {
if (err) {
alert(err);
} else {
alert(data.items[0].snippet.channelId);
}
}
);
function getJSON(url, callback) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// We have the JSON, now we try to parse it
try {
var data = JSON.parse(request.responseText);
// It worked, no error (null)
return callback(null, data);
} catch(e) {
// A parsing arror occurred
console.error(e);
return callback('An error occurred while parsing the JSON.');
}
}
// If an error occurred while fetching the data
callback('An error occurred while fetching the JSON.');
};
request.onerror = function() {
// There was a connection error of some sort
callback('An error occurred while fetching the JSON.');
};
request.send();
}

node.js xmlhttp get request getaddrinfor ENOTFOUND error

Reaching out to see if anyone can let me know where I am going wrong with my code here. I am new to node.js and being behind a corporate proxy is making it tough for me to get going.
I am receiving the below error when trying to make a xmlhttprequest with GET method in node.js. I am using pure JavaScript without any frameworks as you can see from the code below.
Error:getaddrinfo ENOTFOUND xxx-api.xxx.com xxx-api.xxx.com :443
at errnoException (dns.js:28:10)
at GetAddrInforReqWrap.onlookup [as incomplete] (dns.js:76:26)
Image showing error
Since I am behind a proxy, I tried various methods to make 'npm install xxxx' work. Finally, setting "Automatically authenticate" in 'rules' of Fiddler and changing npm config settings as below helped.
registry=http://registry.npmjs.org/
proxy=http://127.0.0.1:8888/
https-proxy=http://127.0.0.1:8888/
http-proxy=http://127.0.0.1:8888
strict-ssl=false
After this, npm install xmlhttprequest worked fine for me. So I proceeded to execute my GET request as below:
function login()
{
return new Promise(function (resolve, reject) {
var url = 'https://xxx-api.xxx.com/v1/login';
var method='GET';
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr)
{
xhr.open(method, url, true);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader('user', 'xxxx');
xhr.setRequestHeader('password','xxxx');
}
else if (typeof XDomainRequest != "undefined")
{
xhr = new XDomainRequest();
xhr.open(method, url);
}
else
{
xhr = null;
}
if (!xhr)
{
console.log('CORS not supported');
}
xhr.onload = function()
{
text = xhr.responseText;
obj=JSON.parse(text);
c=obj.certificate;
if (this.status >= 200 && this.status < 300) {
resolve(xhr.responseText);
}
else {
reject({
status: xhr.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function() {
console.log('There was an error making the request.');
console.log(xhr.statusText);
reject({
status: xhr.status,
statusText: xhr.statusText
});
};
xhr.send();
});
}
You can see I am making a CORS API request here. However, this returns me the above error.
I used nslookup xxx-api.xxx.com and it returned me the server, address and Name perfectly fine. So I suspect this is not a dns or connection issue.
However, if I try the same code on my personal laptop outside the corporate network without changing any proxy settings,everything works as expected.
Any help is greatly appreciated. Thanks in advance!

cannot handle net::ERR_CONNECTION_REFUSED in pure js

I use pure js(without JQuery) to send an XMLHttpRequest request to server.
var _xhr = new XMLHttpRequest();
_xhr.open(type, url);
_xhr.setRequestHeader('Content-Type', 'application/json');
_xhr.responseType = 'json';
_xhr.onload = function () {
if (_xhr.status === 200) {
var _json = _xhr.response;
if (typeof _json == 'string')
_json = JSON.parse(_json);
success(_json);
} else {
error(_xhr);
}
};
_xhr.onerror = function(){
console.log('fail');
};
try {
_xhr.send(_to_send);
} catch (e){
options.error(_xhr);
}
when i send a request it's fails(this is ok) and i get an error but I CANNON HANDLE IT. xhr.onerror prints message to console but i get OPTIONS url net::ERR_CONNECTION_REFUSED too. How can I avoid this message in console?
Also i use window.onerror to handle all error but i can not handle this OPTIONS url net::ERR_CONNECTION_REFUSED
This worked for me:
// Watch for net::ERR_CONNECTION_REFUSED and other oddities.
_xhr.onreadystatechange = function() {
if (_xhr.readyState == 4 && _xhr.status == 0) {
console.log('OH NO!');
}
};
This is not limited to just net::ERR_CONNECTION_REFUSED because other network errors (e.g. net::ERR_NETWORK_CHANGED, net::ERR_ADDRESS_UNREACHABLE, net::ERR_TIMED_OUT) may be "caught" this way. I am unable to locate these error messages within the _xhr object anywhere, so making a programmatic decision about which network error has specifically occurred won't be reliable.
There is no way around that error showing in console. Just as if you request a file that does't exist you get a 404 in console, regardless of if you handle the error or not.

Repeat failed XHR

Is there any common way, example or code template how to repeat a XHR that failed due to connection problems?
Preferably in jQuery but other ideas are welcome.
I need to send some application state data to a database server. This is initiated by the user clicking a button. If the XHR fails for some reason I need to make sure that the data is sent later (no interaction needed here) in the correct order (the user may press the button again).
Here's how I would do it:
function send(address, data) {
var retries = 5;
function makeReq() {
if(address == null)
throw "Error: File not defined."
var req = (window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");
if(req == null)
throw "Error: XMLHttpRequest failed to initiate.";
req.onload = function() {
//Everything's peachy
console.log("Success!");
}
req.onerror = function() {
retries--;
if(retries > 0) {
console.log("Retrying...");
setTimeout(function(){makeReq()}, 1000);
} else {
//I tried and I tried, but it just wouldn't work!
console.log("No go Joe");
}
}
try {
req.open("POST", address, true);
req.send(data); //Send whatever here
} catch(e) {
throw "Error retrieving data file. Some browsers only accept cross-domain request with HTTP.";
}
}
makeReq();
}
send("somefile.php", "data");
To make sure everything is sent in the right order, you could tack on some ID variables to the send function. This would all happen server-side though.
And of course, there doesn't need to be a limit on retries.
jQuery provides an error callback in .ajax for this:
$.ajax({
url: 'your/url/here.php',
error: function(xhr, status, error) {
// The status returns a string, and error is the server error response.
// You want to check if there was a timeout:
if(status == 'timeout') {
$.ajax();
}
}
});
See the jQuery docs for more info.

How do I check if file exists in jQuery or pure JavaScript?

How do I check if a file on my server exists in jQuery or pure JavaScript?
With jQuery:
$.ajax({
url:'http://www.example.com/somefile.ext',
type:'HEAD',
error: function()
{
//file not exists
},
success: function()
{
//file exists
}
});
EDIT:
Here is the code for checking 404 status, without using jQuery
function UrlExists(url)
{
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status!=404;
}
Small changes and it could check for status HTTP status code 200 (success), instead.
EDIT 2: Since sync XMLHttpRequest is deprecated, you can add a utility method like this to do it async:
function executeIfFileExist(src, callback) {
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (this.readyState === this.DONE) {
callback()
}
}
xhr.open('HEAD', src)
}
A similar and more up-to-date approach.
$.get(url)
.done(function() {
// exists code
}).fail(function() {
// not exists code
})
This works for me:
function ImageExist(url)
{
var img = new Image();
img.src = url;
return img.height != 0;
}
i used this script to add alternative image
function imgError()
{
alert('The image could not be loaded.');
}
HTML:
<img src="image.gif" onerror="imgError()" />
http://wap.w3schools.com/jsref/event_onerror.asp
So long as you're testing files on the same domain this should work:
function fileExists(url) {
if(url){
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.send();
return req.status==200;
} else {
return false;
}
}
Please note, this example is using a GET request, which besides getting the headers (all you need to check weather the file exists) gets the whole file.
If the file is big enough this method can take a while to complete.
The better way to do this would be changing this line: req.open('GET', url, false); to req.open('HEAD', url, false);
Here's how to do it ES7 way, if you're using Babel transpiler or Typescript 2:
async function isUrlFound(url) {
try {
const response = await fetch(url, {
method: 'HEAD',
cache: 'no-cache'
});
return response.status === 200;
} catch(error) {
// console.log(error);
return false;
}
}
Then inside your other async scope, you can easily check whether url exist:
const isValidUrl = await isUrlFound('http://www.example.com/somefile.ext');
console.log(isValidUrl); // true || false
I was getting a cross domain permissions issue when trying to run the answer to this question so I went with:
function UrlExists(url) {
$('<img src="'+ url +'">').load(function() {
return true;
}).bind('error', function() {
return false;
});
}
It seems to work great, hope this helps someone!
All the other answers can fail due to cache!
Making a HTTP request to a file on server can be intercepted with HTTP cache and the cached response is then returned. But the file may be deleted on the server in the meantime, so ignoring cache may return false positive results.
Proper solution would be to create non-cached HTTP HEAD request. Nik Sumeiko's answer uses no-cache header which means that the response can be cached, but must be revalidated before reuse. In this case the server may return 304: Not Modified, which is not 200: OK and thus false negative.
To avoid cache, the correct header is Cache-Control: no-store
File can exist without HTTP 200 response
You should also keep in mind that redirection (301: Moved Permanently, 307: Temporary Redirect or 308: Permanent Redirect) may occur, so the file can exist elsewhere and may be returned from different location: depending on the use-case, one may choose to follow redirection instead of returning false in this case.
Also keep in mind that background requests will be blocked if you check file existence on different domain and its CORS policy is not opened to your server. In this case 403: Forbidden is usually returned, which doesn't mean file does not exist but file is unavailable. Last but not least, the same applies to 500: Internal Server Error response, which means that the HTTP server failed to handle the request, but the file can be available otherwise, like by FTP.
The following code will return true if the file exists, false if not or undefined if the file is unavailable or redirected:
const fileExists = file =>
fetch(file, {method: 'HEAD', cache: 'no-store'})
.then(response => ({200: true, 404: false})[response.status])
.catch(exception => undefined);
fileExists("yourFile.html").then(yes => yes && alert("yourFile.html exists"));
// or in the async scope...
let yourFileExists = await fileExists("yourFile.html");
if(yourFileExists) console.log("It is there!")
else if(yourFileExists===false) console.log("Nope, it was deleted.");
else console.log("You are not worthy the answer, puny human!");
Modern and obsolete approaches
Since we live in the future now, I would also recommend:
$.ajax() obsolete, don't use in new projects
XMLHttpRequest() obsolete, don't use in new projects
fetch() modern approach, use it if you are free to choose
Note GET/POST methods (like <img src...>) are not appropriate here as they waste network traffic by downloading the file (imagine the worst scenario with high resolution photo and user with paid mobile data in area with poor connectivity)
Note Modern PWA approach is to use Cache API with serviceWorker's fetch event which intercepts the communication between the client and HTTP cache. In the example in the link, there should be something like
if(event.request.cache=="no-store") {
// avoid cache storage and pass the request in the chain
// client - cache storage - HTTP cache - server
return fetch(event.request);
}
Without this, the cache settings may be ignored and there may be no way to detect the remote file existence from the main thread with the serviceWorker running - illustrated
here.
JavaScript function to check if a file exists:
function doesFileExist(urlToFile)
{
var xhr = new XMLHttpRequest();
xhr.open('HEAD', urlToFile, false);
xhr.send();
if (xhr.status == "404") {
console.log("File doesn't exist");
return false;
} else {
console.log("File exists");
return true;
}
}
I use this script to check if a file exists (also it handles the cross origin issue):
$.ajax(url, {
method: 'GET',
dataType: 'jsonp'
})
.done(function(response) {
// exists code
}).fail(function(response) {
// doesnt exist
})
Note that the following syntax error is thrown when the file being checked doesn't contain JSON.
Uncaught SyntaxError: Unexpected token <
For a client computer this can be achieved by:
try
{
var myObject, f;
myObject = new ActiveXObject("Scripting.FileSystemObject");
f = myObject.GetFile("C:\\img.txt");
f.Move("E:\\jarvis\\Images\\");
}
catch(err)
{
alert("file does not exist")
}
This is my program to transfer a file to a specific location and shows alert if it does not exist
An async call to see if a file exists is the better approach, because it doesn't degrade the user experience by waiting for a response from the server. If you make a call to .open with the third parameter set to false (as in many examples above, for example http.open('HEAD', url, false); ), this is a synchronous call, and you get a warning in the browser console.
A better approach is:
function fetchStatus( address ) {
var client = new XMLHttpRequest();
client.onload = function() {
// in case of network errors this might not give reliable results
returnStatus( this.status );
}
client.open( "HEAD", address, true );
client.send();
}
function returnStatus( status ) {
if ( status === 200 ) {
console.log( 'file exists!' );
}
else {
console.log( 'file does not exist! status: ' + status );
}
}
source: https://xhr.spec.whatwg.org/
This is an adaptation to the accepted answer, but I couldn't get what I needed from the answer, and had to test this worked as it was a hunch, so i'm putting my solution up here.
We needed to verify a local file existed, and only allow the file (a PDF) to open if it existed. If you omit the URL of the website, the browser will automatically determine the host name - making it work in localhost and on the server:
$.ajax({
url: 'YourFolderOnWebsite/' + SomeDynamicVariable + '.pdf',
type: 'HEAD',
error: function () {
//file not exists
alert('PDF does not exist');
},
success: function () {
//file exists
window.open('YourFolderOnWebsite/' + SomeDynamicVariable + '.pdf', "_blank", "fullscreen=yes");
}
});
First creates the function
$.UrlExists = function(url) {
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status!=404;
}
After using the function as follows
if($.UrlExists("urlimg")){
foto = "img1.jpg";
}else{
foto = "img2.jpg";
}
$('<img>').attr('src',foto);
Here's my working Async Pure Javascript from 2020
function testFileExists(src, successFunc, failFunc) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (this.readyState === this.DONE) {
if (xhr.status === 200) {
successFunc(xhr);
} else {
failFunc(xhr);
}
}
}
// xhr.error = function() {
// failFunc(xhr);
// }
// xhr.onabort = function() {
// failFunc(xhr);
// }
// xhr.timeout = function() {
// failFunc(xhr);
// }
xhr.timeout = 5000; // TIMEOUT SET TO PREFERENCE (5 SEC)
xhr.open('HEAD', src, true);
xhr.send(null); // VERY IMPORTANT
}
function fileExists(xhr) {
alert("File exists !! Yay !!");
}
function fileNotFound(xhr) {
alert("Cannot find the file, bummer");
}
testFileExists("test.html", fileExists, fileNotFound);
I could not force it to come back with any of the abort, error, or timeout callbacks.
Each one of these returned a main status code of 0, in the test above, so
I removed them. You can experiment.
I set the timeout to 5 seconds as the default seems to be very excessive.
With the Async call, it doesn't seem to do anything without the send() command.
What you'd have to do is send a request to the server for it to do the check, and then send back the result to you.
What type of server are you trying to communicate with? You may need to write a small service to respond to the request.
This doesn't address the OP's question, but for anyone who is returning results from a database: here's a simple method I used.
If the user didn't upload an avatar the avatar field would be NULL, so I'd insert a default avatar image from the img directory.
function getAvatar(avatar) {
if(avatar == null) {
return '/img/avatar.jpg';
} else {
return '/avi/' + avatar;
}
}
then
<img src="' + getAvatar(data.user.avatar) + '" alt="">
It works for me, use iframe to ignore browsers show GET error message
var imgFrame = $('<iframe><img src="' + path + '" /></iframe>');
if ($(imgFrame).find('img').attr('width') > 0) {
// do something
} else {
// do something
}
I wanted a function that would return a boolean, I encountered problems related to closure and asynchronicity. I solved this way:
checkFileExistence= function (file){
result=false;
jQuery.ajaxSetup({async:false});
$.get(file)
.done(function() {
result=true;
})
.fail(function() {
result=false;
})
jQuery.ajaxSetup({async:true});
return(result);
},

Categories

Resources