I'm trying to write a JavaScript function that gets a foreign url, and attempts to verify its existence within 'tmOut' msecs. If verified within this timeframe, it should call a 'callback' function with this url as an argument.
Here is the function:
function chkUrl(url, tmOut, callback) {
var abortChk = false;
var abortTmr = setTimeout(function(){abortChk = true;}, tmOut);
var x = new XMLHttpRequest();
x.onreadystatechange = function() {
if (x.readyState == 4) {
if (x.status < 400 && !abortChk) {
clearTimeout(abortTmr);
callback(url);
}
}
};
x.open('GET', url, true);
x.send(null);
}
Problem is because of cross-domain calls (probably) I get x.status=0 regardless of the url existence.
Is there a way to overcome/workaround the problem (without the users having to modify any default browser settings)? Alternatively, is there a way to achieve the same functionality otherwise?
Is this function "reentrant"? (can I call it safely several times for different urls at once?)
Is there a way to overcome/workaround the problem
Client side? Only if the sites you are making the request to use CORS to grant you permission (which seems unlikely given the context).
Perform your test from your server instead of directly from the browser.
Is this function "reentrant"? (can I call it safely several times for different urls at once?)
Yes. You aren't creating any globals.
Related
I'm using XMLHttpRequest in JavaScript. However, it gives me an error, and I don't know what my problem is.
I have to parse an XML file and assign its contents to the webpage - here's my code:
<script = "text/javascript">
window.onload = onPageLoad();
var questionNum = 0;
function onPageLoad(questionNum) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","quiz.xml");
try {
xmlhttp.send(null); // Here a xmlhttprequestexception number 101 is thrown
} catch(err) {
document.getElementById("body").innerHTML += "\nXMLHttprequest error: " + err.description; // This prints "XMLHttprequest error: undefined" in the body.
}
xmlDoc = xmlhttp.responseXML;
parser = new DOMParser(); // This code is untested as it does not run this far.
}
</script>
My XML file is inside the same directory.
<question>
<query>what is 2+2?</query>
<option>4</option>
<option>5</option>
<option>3</option>
<answer>4</answer>
</question>
Just for reference, I typically program in C# or Java, and I'm running my website on Google Chrome.
So there might be a few things wrong here.
First start by reading how to use XMLHttpRequest.open() because there's a third optional parameter for specifying whether to make an asynchronous request, defaulting to true. That means you're making an asynchronous request and need to specify a callback function before you do the send(). Here's an example from MDN:
var oXHR = new XMLHttpRequest();
oXHR.open("GET", "http://www.mozilla.org/", true);
oXHR.onreadystatechange = function (oEvent) {
if (oXHR.readyState === 4) {
if (oXHR.status === 200) {
console.log(oXHR.responseText)
} else {
console.log("Error", oXHR.statusText);
}
}
};
oXHR.send(null);
Second, since you're getting a 101 error, you might use the wrong URL. So make sure that the URL you're making the request with is correct. Also, make sure that your server is capable of serving your quiz.xml file.
You'll probably have to debug by simplifying/narrowing down where the problem is. So I'd start by making an easy synchronous request so you don't have to worry about the callback function. So here's another example from MDN for making a synchronous request:
var request = new XMLHttpRequest();
request.open('GET', 'file:///home/user/file.json', false);
request.send(null);
if (request.status == 0)
console.log(request.responseText);
Also, if you're just starting out with Javascript, you could refer to MDN for Javascript API documentation/examples/tutorials.
I see 2 possible problems:
Problem 1
the XMLHTTPRequest object has not finished loading the data at the time you are trying to use it
Solution:
assign a callback function to the objects "onreadystatechange" -event and handle the data in that function
xmlhttp.onreadystatechange = callbackFunctionName;
Once the state has reached DONE (4), the response content is ready to be read.
Problem 2
the XMLHTTPRequest object does not exist in all browsers (by that name)
Solution:
Either use a try-catch for creating the correct object for correct browser ( ActiveXObject in IE) or use a framework, for example jQuery ajax-method
Note: if you decide to use jQuery ajax-method, you assign the callback-function with jqXHR.done()
The problem is likely to lie with the line:
window.onload = onPageLoad();
By including the brackets you are saying onload should equal the return value of onPageLoad(). For example:
/*Example function*/
function onPageLoad()
{
return "science";
}
/*Set on load*/
window.onload = onPageLoad()
If you print out the value of window.onload to the console it will be:
science
The solution is remove the brackets:
window.onload = onPageLoad;
So, you're using onPageLoad as a reference to the so-named function.
Finally, in order to get the response value you'll need a readystatechange listener for your XMLHttpRequest object, since it's asynchronous:
xmlDoc = xmlhttp.responseXML;
parser = new DOMParser(); // This code is untested as it doesn't run this far.
Here you add the listener:
xmlHttp.onreadystatechange = function() {
if(this.readyState == 4) {
// Do something
}
}
I have found a geocoder website that will give me some data that I need as a variable in my javascript code: http://geocoder.us/service/csv/geocode?zip=95472. the website returns only the content: 38.393314, -122.83666, Sebastopol, CA, 95472. I need pull this information from the website and put it into a string.
abc = "38.393314, -122.83666, Sebastopol, CA, 95472"
How can I accomplish this?
You can use AJAX:
var req = new XMLHttpRequest(); //Create an AJAX object
req.open('GET','http://geocoder.us/service/csv/geocode?zip=95472',true); //Location and method
req.send(); //Send
req.onreadystatechange = function() { //When it's ready
if (this.readyState === 4) { //... which is code 4
console.log(this.responseText); //Then you have the responseText
}
}
This only works when the request is from the same domain, tho (for security purposes). If you want it to work on any domain, you'll have to use a proxy.
You should use Javascript to make an ajax request to that URL and it will return the information you want in a format you specify, usually JSON. Depending on what Javascript libraries you are/aren't using, there's different ways you could do that -- probably the most common would be to use jQuery to make your request. Here's info on that API:
https://api.jquery.com/jQuery.get/
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 want to make a little web page which calculates stuff, based on various data from another site. Let's say for an online browser game.
I would like to have it take some specific details from the web pages on the game, but I don't even know where to start.
Is this doable with javascript (if not I would like to know with what language it is)? Could anyone give me a general of guideline of how this can be done?
You can use a combination of AJAX and XMLHTTPRequest, but these are subject to the same origin policy.
Of course, it would make it a lot easier if the external site can send back data in JavaScript Object Notation format (JSON) for readability.
There is a similar question asked here for how to obtain the contents of an external site using XMLHTTPRequest here: How to specify an external website for XMLHTTPRequest
There is another similar question on using XMLHTTPRequest and JSON: Cross-domain JSON request?
I have a standard function for using AJAX to get information dynamically. I use PHP as my listener. Your listener would have to be able to accept variables from the URL, like PHP $_GET[].
In the example below, your listener named "source_url.php" would have to check the values received in $_GET[field] and then simply print/echo the result.
JAVASCRIPT:
function get_(url, func)
{
var http;
try { http = new XMLHttpRequest(); } catch (e) { try { http = new ActiveXObject(\"Msxml2.XMLHTTP\"); } catch (e) { try { http = new ActiveXObject(\"Microsoft.XMLHTTP\"); } catch (e) { alert(\"Your browser broke!\"); return false; } } }
http.open(\"GET\", url, true);
http.onreadystatechange = function() { if(http.readyState == 4) { func(http); } }
http.send(null);
}
function get_info(fieldname)
{
get_("source_url.php?field=" + fieldname, showResult)
}
function showResult(h)
{
alert("The result is: " + h.responseText);
}
HTML
<button onClick='get_info("name");'>Get the ship Name</button>
<button onClick='get_info("reg");'>Get the Registration Number</button>
<button onClick='get_info("capt");'>Who is the Captain?</button>
PHP
<?php
if ($_GET[field] == "name") { print "U.S.S. Enterprise"; }
if ($_GET[field] == "reg") { print "NCC - 1701"; }
if ($_GET[field] == "capt") { print "Jean Luc Picard"; }
?>
I use this all the time, though I have created a more advanced version with authentication security. This is where you should start if you are just learning how AJAX works.
Suppose I have
1)
a HTML document.
2)
This HTML document loads Javascript file "code.js" like this:
<script src="code.js">
3)
User clicks button which runs "fetchdata" function in "code.js",
4)
"fetchdata" function looks like this:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState==4) {
myjsdata = xmlhttp.responseText;
}
}
xmlhttp.open("GET", 'http://www.example.com/data.js', false);
xmlhttp.send(null);
...
Now how do I do the following successfully:
I want to insert/eval my Javascript in a way, so all functions in "code.js" including "fetchdata" and functions defined above/below can access the data (structures, declarations, pre-calculated data values etc.) in "data.js".
(If this was possible, it would be idea since I could wait loading the actual JS data file until the user explicitly requests it.)
jQuery always has something for everything:
http://api.jquery.com/jQuery.getScript/
Loads a javascript file from url and executes it in the global context.
edit: Oops, didn't see that you weren't using jQuery. Everyone is always using jQuery...
Just do:
var scrpt = document.createElement('script');
scrpt.src='http://www.example.com/data.js';
document.head.appendChild(scrpt);
i think you should take a look at this site
this site talks about dynamic loading and callbacks (with examples) - where you can call a function in the loaded script after it loads. no jQUery, just pure JS.
This depends on a lot of factors, but in most cases, you will want to load all of your code/html/css in one sitting. It takes fewer requests, and thus boast a higher perceived performance benefit. Unless your code file is over several Megabytes big, loading it when a user requests it is unnecessary.
In addition to all of this, modifying innerHTML and running scripts via eval can be very cumbersome and risky (respectively). Many online references will back this point. Don't assume that, just because a library is doing something like this, it is safe to perform.
That said, it is entirely possible to load external js files and execute them. One way is to stick all of the code into a newly created script tag. You can also just try running the code in an eval function call (though it isn't recommended).
address = "testscript.js";
var req = (window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");
if(req == null) {
console.log("Error: XMLHttpRequest failed to initiate.");
}
req.onload = function() {
try {
eval(req.responseText);
} catch(e) {
console.log("There was an error in the script file.");
}
}
try {
req.open("GET", address, true);
req.send(null);
} catch(e) {
console.log("Error retrieving data httpReq. Some browsers only accept cross-domain request with HTTP.");
}