Detect 404 for resources via JavaScript - javascript

is there a way to detect resources on the page with response 404?
Also why the browser api- performance.getEntriesByType("resource") doesn't include the failed resources?

Well, with this function :
function UrlExists(url) {
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
if (http.status == 404) {
// do something
}
}
And you pass the URL of your resource. but it's not the best solution ever to check this. Let's say it's the simplest :)
EDIT :
After you can also do it for every kind of resources (CSS, Images, ...), a function like this one :
var styleSheetExists = function(name) {
for (var i in document.styleSheets) {
if (typeof document.styleSheets[i] == "object") {
link = document.styleSheets[i].href;
if (link === null) {
continue;
}
if (link.indexOf(name, link.length - name.length) !== -1) {
return true;
}
}
}
return false;
}
That you can use like :
$(document).ready(function() {
console.log(styleSheetExists('jquery-ui.css'));
console.log(styleSheetExists('doesnotexist.css'));
});
(Source of the function : How to check for 403 and 404 errors when changing the url of a resource?)
and by checking every kind of resource, you can assure that there is or not a 404 status about them.

Related

good practice to change page without reloading

I am trying to change page but without any reloading
here's what I do:
AJAX:
app.ajax.client.request = function(headers, path, method, queryObj, payload, cb) {
// Set defaults
headers = typeof(headers) == 'object' && headers !== null ? headers : {};
path = typeof(path) == 'string' ? path : '/';
method = typeof(method) == 'string' && ['POST','PUT','DELETE','GET'].indexOf(method.toUpperCase()) > -1 ? method.toUpperCase() : 'GET';
queryObj = typeof(queryObj) == 'object' && queryObj !== null ? queryObj : {};
payload = typeof(payload) == 'object' && payload !== null ? payload : {};
cb = typeof(cb) == 'function' ? cb : false;
// For each query string parameter sent, add it to the path
let requestUrl = path + '?';
let counter = 0;
// Set the request url based on the query object
for (let i in queryObj) {
if (queryObj.hasOwnProperty(i)) {
counter++
if (counter > 1) {
requestUrl += '&';
}
requestUrl += i + '=' + queryObj[i];
}
}
// Form the http request as a JSON type
let xhr = new XMLHttpRequest();
xhr.open(method, requestUrl, true);
xhr.setRequestHeader('Content-Type', 'application/json');
// For each header sent, add it to the request
for (let i in headers) {
if (headers.hasOwnProperty(i)) {
xhr.setRequestHeader(i, headers[i]);
}
}
// When the request comes back, handle the response
xhr.onreadystatechange = function() {
// Set the parameters that will be called back
let readyState = xhr.readyState;
let statusCode = xhr.status;
let responseReturned = xhr.responseText;
// Parse the response
let parsedResponse = app.isJsonString(responseReturned);
if (parsedResponse) { // If the response text is a JSON, callback parsedResponse, if not, callback the not parsed response instead
cb(readyState, statusCode, parsedResponse);
} else {
cb(readyState, statusCode, responseReturned);
}
}
// Send the payload as JSON
let payloadString = JSON.stringify(payload);
xhr.send(payloadString);
}
Client Requests:
app.changeToIndexPage = function(e) {
e.preventDefault();
if (!app.mainContainer.hasClass('index')) {
app.closePage(); // show a loading screen
history.pushState({}, '', '/'); //Set the url to the index's url
setTimeout(function() {
app.ajax.client.request(undefined, 'public/request/index.txt', 'GET', undefined, undefined, function(readyState, statusCode, response) { // Get the request
console.log(readyState);
if (readyState < 3) {
app.preloader.addClass('loading');
} else if (readyState == 4 && statusCode == 200) {
app.navContainer.attr('class', app.navContainer.attr('class').replace(/index|project|about|contact/g, 'index'));
setTimeout(function() {
app.mainContainer.html(response);
}, 500);
}
});
}, 100);
}
}
So, for example:
If I am not on the index page, and wanted to go to the index page, i can run the changeToIndexPage function, and the ajax will request the needed file and change the html element based on the needed action. The only problem that I had is, are there any better solution??
If you're going to take the approach of fetching pages with AJAX and slapping them into the document, which I wouldn't recommend in the first place, you should have a generalized function to do so.
That function should have a signature like function navigate(path) { ... }. It should add the history entry, fetch the appropriate document and insert it onto the page.
Then, you'll need to attach an event listener to catch popState events, so when the user presses the back button you retrieve the path from the history entry that was popped and pass it to navigate().
Again, if you're looking to build an SPA I wouldn't recommend building it like this. One of the major benefits of SPAs are the performance gain from rendering your documents on the client, which this approach doesn't leverage. Consider using a component-based client-side rendering library like React or Angular.

How to detect if a file exists in JavaScript accounting for 404 handler

In my website I am currently trying to write code to turn a link into a formatted attachment .
I am trying to write code to detect if the file exists
function doesFileExist(urlToFile) {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', urlToFile, false);
if (xhr.status == "404") {
return false;
} else {
return true;
}
}
alert(doesFileExist("http://hexbugman213.net/favicon.png"));
However, I noticed a problem. When the website has a 404 handler like .htaccess, and I try to test it with the file, it sees that the website didn't return a 404, and therefore still says it exists.
function doesFileExist(urlToFile) {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', urlToFile, false);
if (xhr.status == "404") {
return false;
} else {
return true;
}
}
alert(doesFileExist("http://hexbugman213.net/thisfiledoesntexist.mp3"));
Is there any way I can account for this and have it return "false" when the file doesn't exist even if there's a 404 handler?
You need to call the send() function on the XMLHttpRequest to make it actually make the request. See: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send
Also, you may run into cross origin issues depending on exactly what URL you're trying to retrieve and where you're hosting the page from. Mozilla has some documentation on the subject if you're not familiar with it: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Here is an improved version of your JavaScript that checks for exceptions and calls the send() function.
function doesFileExist(urlToFile) {
try {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', urlToFile, false);
xhr.send();
alert(xhr.status)
if (xhr.status !== 200) {
return false;
} else {
return true;
}
} catch (e) {
alert(e);
return false;
}
}
alert(doesFileExist("https://server.test-cors.org/server?enable=true&status=200&credentials=false"));
alert(doesFileExist("https://server.test-cors.org/server?enable=true&status=404&credentials=false"));
alert(doesFileExist("https://www.google.com/"));
alert(doesFileExist("http://hexbugman213.net/thisfiledoesntexist.mp3"));
The host: https://www.test-cors.org/ in the example is useful for testing CORS.

Can't make cross-domain requests without jQuery

I'm working on a web project where using jQuery (or other libraries/dependencies) is not an option, so I'm trying to replicate the code jQuery uses to make AJAX requests. The project previously used jQuery, so I've structured my replacement to the $.ajax() method to have the same behavior, however I cannot get mine to make cross-domain requests. When trying to load in scripts for example, I get this error in the console.
XMLHttpRequest cannot load <URL>. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin <URL> is therefore not allowed access.
I'm familiar with CORS and the whole cross-origin-security policy and what that entails, but what I'm confused about is how jQuery can seem to circumvent that, while my code cannot. I'm thinking there must be something special jQuery is doing?
This is how my $.ajax() replacement function is currently scripted.
function ajax (options) {
var request = new XMLHttpRequest();
if ("withCredentials" in request)
request.withCredentials = false;
else if (typeof XDomainRequest !== "undefined")
var request = new XDomainRequest();
options.type = options.type || options.method || "GET";
request.open(options.type.toUpperCase(), options.url, true);
for (var i in options.headers) {
request.setRequestHeader(i, options.headers[i]);
}
if (typeof options.beforeSend == "function")
var go = options.beforeSend(request, options);
if (go == false)
return false;
request.onreadystatechange = function () {
if (this.readyState === XMLHttpRequest.DONE) {
var resp = this.responseText;
try {
var body = JSON.parse(resp);
this.responseJSON = body;
}
catch (err) {
var body = resp;
}
if (this.status < 300 && typeof options.success == "function")
options.success(body, this.status, this);
else if (typeof options.error == "function")
options.error(this, this.status, body);
if (typeof options.complete == "function")
options.complete(this, this.status);
}
};
if (typeof options.data == "object" && options.data !== null)
options.data = JSON.stringify(options.data);
if (options.type.toUpperCase() != "GET")
request.send(typeof options.data !== "undefined" ? options.data : null);
else
request.send();
return request;
}
Can someone point out if I'm missing something obvious? Do I need to manually also do the OPTIONS pre-flight or something?
I've found a fix for this. The issue seemed to stem from trying to load in cross-domain scripts specifically. jQuery uses $.getScript() to do that, which actually just adds a script to the page instead of making a cross-domain HTTP request.
I used this code as a replacement for that function.
function getScript (url, callback) {
var loadScript = function (url, callback) {
var scrpt = document.createElement("script");
scrpt.setAttribute("type", "text/javascript");
scrpt.src = url;
scrpt.onload = function () {
scrpt.parentNode.removeChild(scrpt);
console.log("Script is ready, firing callback!");
if (callback)
callback();
};
document.body.appendChild(scrpt);
}
var isReady = setInterval(function () {
console.log(document.body);
if (document.body) {
clearInterval(isReady);
loadScript(url, callback);
}
}, 25);
}

Synchronous XMLHttpRequest on the main thread is deprecated

I am working on extjs framework..
i have an application running on extjs..
whenever i open the application in the browser...i see the following
warnings in my console...
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/
can you guys tell me how to remove it..
when i click the warning it takes to ext-all-debug-w-comments.js file
and points to the following part of code...
try {
xhr.open('GET', noCacheUrl, false);
xhr.send(null);
} catch (e) {
isCrossOriginRestricted = true;
}
can you guys tell me how to prevent it from happening...
providing my code below in that file
/**
* Load a script file, supports both asynchronous and synchronous approaches
* #private
*/
loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
if (isFileLoaded[url]) {
return Loader;
}
var config = Loader.getConfig(),
noCacheUrl = url + (config.disableCaching ? ('?' + config.disableCachingParam + '=' + Ext.Date.now()) : ''),
isCrossOriginRestricted = false,
xhr, status, onScriptError,
debugSourceURL = "";
scope = scope || Loader;
Loader.isLoading = true;
if (!synchronous) {
onScriptError = function() {
};
scriptElements[url] = Loader.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
} else {
if (typeof XMLHttpRequest != 'undefined') {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
try {
xhr.open('GET', noCacheUrl, false);
xhr.send(null);
} catch (e) {
isCrossOriginRestricted = true;
}
status = (xhr.status === 1223) ? 204 :
(xhr.status === 0 && (self.location || {}).protocol == 'file:') ? 200 : xhr.status;
isCrossOriginRestricted = isCrossOriginRestricted || (status === 0);
if (isCrossOriginRestricted
) {
}
else if ((status >= 200 && status < 300) || (status === 304)
) {
// Debugger friendly, file names are still shown even though they're eval'ed code
// Breakpoints work on both Firebug and Chrome's Web Inspector
if (!Ext.isIE) {
debugSourceURL = "\n//# sourceURL=" + url;
}
Ext.globalEval(xhr.responseText + debugSourceURL);
onLoad.call(scope);
}
else {
}
// Prevent potential IE memory leak
xhr = null;
}
},
This warning is only showing in Chrome in the development environment of ExtJs. Once the application is built with sencha cmd, the warning doesn't show anymore. As #Evan pointed out the warning looks benign, and you should not have to worry about it.
The fact that there is a warning should not be an issue, since it will never show in a deployed application. If you do not yet use sencha cmd, it is definitely worth to integrate it in your development cycle.
I know it is not a direct answer to the question. Myself, I wonder if it is possible to get rid of this warning at all.

Javascript HTTP GET html/text returning null/empty?

I am trying to get the html of a website using this code:
function catchData(req) {
console.debug("i got a reply!");
var returnXML = req.responseXML;
console.debug(returnXML);
if (!returnXML)
{
console.debug("html is bad");
return;
}
if (speed != currentSpeed)
moveToNewSpeed(speed);
currentSpeed = speed;
var error = returnXML.getElementsByTagName('message')[0].firstChild;
if (error) {
document.getElementById('errorMessage').innerHTML = error.nodeValue;
document.getElementById('errorMessage').style.visibility = 'visible';
}
else
document.getElementById('errorMessage').style.visibility = 'hidden';
}
function sendRequest(url,callback,postData) {
console.debug(url);
console.debug(postData);
var req = createXMLHTTPObject();
if (!req) return;
var method = (postData) ? "POST" : "GET";
console.debug(method);
req.open(method,url,true);
console.debug("request Opened");
req.setRequestHeader('User-Agent','XMLHTTP/1.0');
req.setRequestHeader('User-Agent','XMLHTTP/1.0');
if (postData)
{
req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
console.debug("set post data");
}
req.onreadystatechange = function () {
if (req.readyState != 4)
{
console.debug("bad ready state");
return;
}
console.debug(req);
console.debug("responseText:");
console.debug(req.responseText);
callback(req);
console.debug("callback finished");
}
if (req.readyState == 4) return;
req.send(postData);
}
var XMLHttpFactories = [
function () {return new XMLHttpRequest()},
function () {return new ActiveXObject("Msxml2.XMLHTTP")},
function () {return new ActiveXObject("Msxml3.XMLHTTP")},
function () {return new ActiveXObject("Microsoft.XMLHTTP")}
];
function createXMLHTTPObject() {
var xmlhttp = false;
for (var i=0;i<XMLHttpFactories.length;i++) {
try {
xmlhttp = XMLHttpFactories[i]();
}
catch (e) {
continue;
}
break;
}
return xmlhttp;
}
When I do a wireshark grab I see the server returning the html, but req.responseText is just an empty string. Anyone know whats up?
I guess you're trying to get the HTML of a page that's on a different domain than your JavaScript. This is a cross-domain request, which isn't allowed in Javascript. This is usually seen as empty responses in your script.
The JSONP standard describes a mechanism to retrieve JSON from a different domain, but this needs to be implemented on the other site and doesn't work with HTML.
The Yahoo! Query Language (YQL) can act as a proxy. The Yahoo! server will fetch the HTML and create a JSONP response, which your script will receive. This may help you to accomplish your goal. The YQL has a lot of cool features for retrieving content from other sites, I recommend you read through the documentation to see if there's anything else you can use.
from where is the javascript being executed? Do you have a same-origin policy violation?
I ask because I have seen wierdness in these situations, where I was violating the policy but the request was still going out; just the response was empty...it doesn't make any sense that the browser would send the request, but they all handle it differently it appears...
Is there a reason why you're writing this code yourself instead of using a library such as jQuery? You'll find it much easier and they've already figured out all the associated quirks with browser interoperability, etc.

Categories