In my webapp I need to check if another server (on a different ip address) is up. I know I can't use direct ajax requests for this because of cross domain restrictions. I cannot use JSONP because I don't have any control over the other server. I also need to repeatedly check for the server being up as it may be unavailable some of the time. All these don't make it easy.
However since I only care about a request to the remote server succeeding (and I don't care about any data that the server might return), I was hoping that it would be possible.
I can't do this on the server side because the server side may or may not have visibility to the other server, what I really care about is that the client (web browser) have visibility.
I can append a new iframe to the page with the src equal to the remote server address but then how can I check when (IF) an iframe contents have been loaded successfully? Also how do I make periodic requests? By creating new iframes repeatedly? That seems quite unclean.
Is there any way to do this cleanly and reliably?
function testServer(server, cb) {
var img = new Image();
img.onload = function() {
cb.call(this, img);
};
img.src = server;
}
var url = "http://placekitten.com/200/300/"
testServer(url, function _self(img) {
if (img.naturalHeight === 200) {
alert("win");
} else {
setInterval(function() {
testServer(url, _self);
}, 10000);
}
});
You want to load an Image from a remote server then check that the image height or whatever is what you expect it is.
If you can't place an image on the remote server then you will need to use CORS
A similar solution to Raynos' using jQuery:
$('<img src="http://domain.tld/path/to/a.png">').load(function(){
console.log("domain.tld is up.");
});
I know I can't use ajax for this because of cross domain restrictions.
Not true. See JSONP
Related
I wonder if that is possible to handle missing resources of a web page all togather including missin images from background: url(...) from CSS.
I have checked document.addEventListener("error", eventHandler, true);, window.onerror and also performance.getEntries() but none of them reports missing images referenced from CSS even from inlined styles.
Best base to also handle missing resources from other origins e.g. broken fonts referenced from CDNs.
A possible solution could be to list all resources using window.performance.getEntriesByType("resource"), then try to download each of them using ajax to see if it produces a 404. However there are 2 major drawbacks to consider:
this isn't an event listener, you have to execute the check after a reasonable amout of time to let the browser load all resources, or execute it periodically;
you must avoid to check for dynamic resources which could return a different result from the previous call, or the more dangerous case where a call to a resource produces an update of the data on the remote server (a very trivial example could be a view counter on an image);
there is a chance that the ajax call results in different status code even if the resource is static, for example if the client is on an unstable network and the connection goes down between the two calls.
Anyway here is a starting point:
window.onload = function() {
setTimeout(function() {
var resources = window.performance.getEntriesByType("resource");
resources.forEach(function (resource) {
$.get(resource.name).fail(function(e) {
var msg = 'Failed to load resource '+resource.name+' requested by '+resource.initiatorType;
var div = $('<div/>').text(msg);
$('body').append(div);
});
});
}, 1000);
};
body {
background-image: url('bar.jpg');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<img src="foo.jpg"/>
This question has been asked a much time, but I am unable to get a perfect answer to implement. So I give it a try asking one more time.
Suppose you wish to show a message when your file has be completely downloaded from the server. Yes, there are possible ways for uploading a file, and even showing a progress bar on download, but is there any particular instance/information/event which should tell when the download has been completed?
All I yet know is that might be it can be implemented with the help of cookies may be. But how?
When you request a file from your server, send a unique key to the download service from the client.
GET /Download?fileId=someId&cookieName=abc
When the server has finished serving the file contents, set a cookie with the unique name
var cookieName = Request.QueryString["cookieName"];
Response.Cookies.Add(new HttpCookie(cookieName , "true")
{
Path = "/",
HttpOnly = false
});
Meanwhile, in your JavaScript, listen for a cookie with your unique name on it and once it is set, do a callback:
window.setInterval(function () {
var cookie = $.cookie('abc');
if (cookie !== null) {
callback();
}
}, 500);
You might also want to look into deleting the cookie when you are done.
I let users on my VanillaForums forum choose whether or not to use the https protocol and I want to test if I can change image sources on the client's side using jQuery.
I want this code to change the protocol in the image source links to // instead of http:// and load before the images have loaded, so I used .ready():
$(document).ready(function () {
if (window.location.protocol == "https:") {
var $imgs = $("img");
$imgs.each(function () {
var img_src = $(this).prop("src");
if (img_src.indexOf("http://") < 0) return;
var new_img_src = img_src.replace("http:", "");
$(this).prop("src", new_img_src);
});
}
});
While it does work in changing the image sources, the URL bar still shows this:
And the console gives a warning that http://someimageurl... is not secure.
Do I need to move the code to the top of the page or will that not make a difference?
It needs to be done server side for the browser not to throw an insecure connection warning. The file with the responsible code is /library/core/functions.render.php, which you can see here.
$PhotoURL is the variable that needs to be changed. Using the following makes sure all images are loaded over the https: protocol: str_replace('http://', 'https://', $PhotoURL).
I usually don't mind global scope on smaller software but in something as big as Vanilla it's like finding a needle in a haystack.
I couldn't find any other fixes for Vanilla in particular so I hope this helps people.
Disclaimer
Firstly, a disclaimer: I am working within specific boundaries, so whilst it may seem I'm going about something the long way round, I am limited as to what I can do. I know I should be doing this entirely differently, but I cannot. If it's not possible to do what I'm trying to do here, then that's fine, I just need to know.
Background
Basically, this boils down to a cross-domain javascript call. However, I need to wait for the response before returning the method.
Say I have a page - example1.com/host.html. This contains a javascript method of 'ProvideValue()' which returns an int. Edit: This method must be executed where it is found, since it may need to access other resources within that domain, and access global variables set for the current session.
https://example1.com/host.html
function ProvideValue(){
return 8; // In reality, this will be a process that returns a value
}
This host.html page contains an iframe pointing to example2.com/content.html (note the different domain). This content.html page contains a method that needs to display the value from host.html in an alert.
https://example2.com/content.html
function DisplayValue(){
var hostValue = //[get value from ProvideValue() in host.html]
alert(hostValue);
}
That's it.
Limitations
I can run any javascript I like on the host.html, but nothing server-side. On content.html I can run javascript and anything server-side. I have no control over the example1.com domain, but full control over example2.com.
Question
How can I retrieve the value from ProvideValue() on example1.com/host.html within the DisplayValue() method on example2.com/content.html?
Previous Attempts
Now, I've tried many of the cross-domain techniques, but all of them (that I've found) use an asynchronous callback. That won't work in this case, because I need to make the request to the host.html, and receive the value back, all within the scope of a single method on the content.html.
The only solution I got working involved relying on asynchronous cross-domain scripting (using easyXDM), and a server-side list of requests/responses in example2.com. The DisplayValue() method made the request to host.html, then immediately made a synchronous post to the server. The server would then wait until it got notified of the response from the cross-domain callback. Whilst waiting, the callback would make another call to the server to store the response. It worked fine in FireFox and IE, but Chrome wouldn't execute the callback until DisplayValue() completed. If there is no way to address my initial question, and this option has promise, then I will pose this as a new question, but I don't want to clutter this question with multiple topics.
Use XMLHttpRequest with CORS to make synchronous cross-domain requests.
If the server doesn't support cors, use a proxy which adds the appropriate CORS headers, e.g. https://cors-anywhere.herokuapp.com/ (source code at https://github.com/Rob--W/cors-anywhere).
Example 1: Using synchronous XHR with CORS
function getProvidedValue() {
var url = 'http://example.com/';
var xhr = new XMLHttpRequest();
// third param = false = synchronous request
xhr.open('GET', 'https://cors-anywhere.herokuapp.com/' + url, false);
xhr.send();
var result = xhr.responseText;
// do something with response (text manipulation, *whatever*)
return result;
}
Example 2: Use postMessage
If it's important to calculate the values on the fly with session data, use postMessage to continuously update the state:
Top-level document (host.html):
<script src="host.js"></script>
<iframe name="content" src="https://other.example.com/content.html"></iframe>
host.js
(function() {
var cache = {
providedValue: null,
otherValue: ''
};
function sendUpdate() {
if (frames.content) { // "content" is the name of the iframe
frames.content.postMessage(cache, 'https://other.example.com');
}
}
function recalc() {
// Update values
cache.providedValue = provideValue();
cache.otherValue = getOtherValue();
// Send (updated) values to frame
sendUpdate();
}
// Listen for changes using events, pollers, WHATEVER
yourAPI.on('change', recalc);
window.addEventListener('message', function(event) {
if (event.origin !== 'https://other.example.com') return;
if (event.data === 'requestUpdate') sendUpdate();
});
})();
A script in content.html: content.js
var data = {}; // Global
var parentOrigin = 'https://host.example.com';
window.addEventListener('message', function(event) {
if (event.origin !== parentOrigin) return;
data = event.data;
});
parent.postMessage('requestUpdate', parentOrigin);
// To get the value:
function displayValue() {
var hostName = data.providedValue;
}
This snippet is merely a demonstration of the concept. If you want to apply the method, you probably want to split the login in the recalc function, such that the value is only recalculated on the update of that particular value (instead of recalculating everything on every update).
i have two paths like:
a) localhost/firstapplication/
b) localhost/secondapplication/images
in firstapplication i do a ajax-request to secondapplication/html/index.html. e.g. i fetch the whole responsetext.
in secondapplication there are some img-tags:
<img src="../images/testpicture.png" alt="test" />
my problem: if i append the whole responsetext my browser is looking for the images.. the link is relative, wich means in: firstapplication/images.
But i want the images of the secondapplication.
Is there any way to get them really easy? Or do i have to change all values of the src-attributes in each img tag from "../images" to a fix path like "localhost/secondapplication/images/"?
thanks for support.
im working with prototype js 1.7 and i'd prefere a solution with this framework. thanks!
If firstapplication and secondapplication are on different domains the AJAX will not work due to Same Origin Policy. As such, I have not given a response to your image problem because once deployed on live your code will not work.
I see a few possibilities
Use an iframe instead of AJAX.
Have the second domain serve absolute URLs.
Manipulate the URLs when the AJAX completes.
new Ajax.Updater('secondapplication/html/index.html', 'ELEMENT_ID', {
onSuccess: function(response){
var receiver = $(this.container.success);
var otherDomain = 'http://localhost/secondapplication/';
var selector = '[src]:not([src^=/]):not([src^=http])';
receiver.select(selector).each(function(element) {
element.src = otherDomain+element.readAttribute('src');
});
selector = '[href]:not([href^=/]):not([href^=http]):not([href^=#])';
receiver.select(selector).each(function(element) {
element.href = otherDomain+element.readAttribute('href');
});
}
});
// otherDomain must end in a solidus, /
// not tested