This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How does AJAX work?
Note: This is a community wiki post
I've often heard of AJAX being used for providing a user with dynamic content. What is it and how does it work?
AJAX, or (A)synchronous (J)avascript (A)nd (X)ML (which interestingly enough tends to use JSON more these days), is a system in which Javascript uses a browser object to communicate with a remote server. The general use case of this is to be able to update a client's interface without needing to go to another page. Before we begin though, a few words of caution.
Ajax is not recommended for login authentication and posting forms
Users can turn off Javascript, or may be restricted from running Javascript due to IT policies
With this in mind it is advised that you do not use AJAX as the sole solution for critical user functionality! Always have a fallback!
Note: This community wiki post uses JQuery to show the example AJAX calls. It's recommended for newcomers as it hides the browser compatibility issues of making AJAX calls. Please check the JQuery website for more information on JQuery.
Note: The examples use communication with a PHP server, but any server side language will work.
AJAX Callbacks
First we have an AJAX call. In the AJAX call you setup callback handlers for the different types of events that can occur. A common misconception can be shown in the following code:
// Incorrect!
function makeAjaxCall() {
var result = $.ajax({
url: 'ajax/test.html'
});
return result;
}
The problem here is that when your browser makes an AJAX request, it can either come back successful, or as a failure. For example if you try an access a page that doesn't exist, or if the server has an internal error. To keep things as organized as possible, AJAX requires that you create callback functions to handle the data request. The correct way is as follows:
// Correct!
function makeAjaxCall() {
$.ajax({
url: 'ajax/test.html',
success: function(data) {
alert('Horray the AJAX call succeeded!');
},
error: function(xhr, error) {
alert('Holy errors batman!');
}
});
}
The Nature of AJAX Calls
AJAX calls can be either Asynchronous or Synchronous. Asynchronous means that the browser will make the AJAX request and continue doing other things. Synchronous means the browser will stop what it's doing until the AJAX call completes. Here is an example of the differences in the two code wise:
// An asynchronous call
// This is the default
$.ajax({
url: '/server.php',
success: function(data) {
alert('Horray the AJAX call succeeded!');
},
error: function(xhr, error) {
alert('Holy errors batman!');
}
});
// This will get called right away
myFunction();
Now for a synchronous call:
// A synchronous call
$.ajax({
url: '/server.php',
async: false, // set the property here
success: function(data) {
alert('Horray the AJAX call succeeded!');
},
error: function(xhr, error) {
alert('Holy errors batman!');
}
});
// This won't get called until the AJAX returns!
myFunction();
WARNING: Synchronous calls make it so the browser can't do anything until the browser completes the call. This could potential lock up the browser! Only use this if you REALLY KNOW WHAT YOU'RE DOING! 99% of the time you want asynchronous AJAX calls.
Note: Synchronous calls don't mean you can get out of not setting callback handlers. You still have to deal with the results using callbacks.
The Client->Server Communication Path
This image illustrates how AJAX is used to communicate with a remote server. First the AJAX code interfaces with a browser object, which makes the actual call to the server. The server then processes the request and sends the result back to the browser, which then looks at the result of the call to determine if it needs to call the success handler, or the error handler. However, there is one issue that can prevent communication at all, which is commonly known as the same origin policy.
Note From the perspective of the server, the AJAX call will look as if the client had made the request manually. That means the server can utilize things like sessions and other client specific data.
Same Origin Policy
The same origin policy basically means that if your AJAX call is from a page hosted on http://www.mysite.com, you can't make a call to http://www.othersite.com as illustrated here:
One way that you can get around this is through a proxy service. This is where you interface with a script on the same server, which in turn interfaces with the site you wish, through CURL calls for example. The following illustrates this proxy method in question:
WARNING Note that the third party server will not see the request as coming from the client, but as coming from the server. Some servers frown upon the same IP making many calls to their servers. This could get you blocked, so verify that the site in question is okay with this setup.
Note: There are some instances where same origin policy doesn't apply, such as Google Chrome extension calls (you have to set permissions for each site though), certain Greasemonkey calls, and Adobe Air.
Now the final concept to go over is how the server returns data for the client to interact with.
AJAX Data Return
Since it's a very popular option, we'll use JSON, or (J)ava(S)cript (O)bject (N)otation, to pass back the data. JSON basically looks like this:
{
color: "red",
value: "#f00"
}
This string can be turned into a JavaScript object, providing easy access to the server results.
WARNING Since this is valid JavaScript, many people use eval() to quickly create js objects. Please don't do this. It opens you up to security issues if the result has malicious code in it. Always use a JSON parser that checks for secure data!
Using the previous example, we can access the different values like so:
$.ajax({
url: '/server.php',
// It's a good idea to explicitly declare the return type
dataType: 'json',
success: function(json) {
alert("The color is: " + json.color + " and the value is: " + json.value);
},
error: function(xhr, error) {
alert('Holy errors batman!');
}
});
Notice how easy it is to access the values of the return. Another popular option is to retrieve HTML from a server and inject it into a <div> or other element. Here is an example of this:
$.ajax({
url: '/server.php',
// It's a good idea to explicitly declare the return type
dataType: 'html',
success: function(html) {
$("#mydiv").html(html);
},
error: function(xhr, error) {
alert('Holy errors batman!');
}
});
// Some JS/HTML here
<div id="mydiv"></div>
In the case of a successful return, the contents of the <div> will be populated with the return HTML.
TODO: Dealing with securing against malicious HTML injection?
Conclusion
This concludes the community wiki post on AJAX. I hope it will be useful in helping you understand AJAX, or as an easy way to answer common questions about it.
Related
I'm fairly new to JS and have a question. Would it be possible to pull data off from another website to use in your own? For example, say I have a JS web app that lets a user input their Twitter username and then the script goes to this username and looks for the follower count element and pulls that number off to display back in the web app. I'm sure there are APIs and such to do something like that specific Twitter example, but I'm getting more at the general idea of being able to access data on other sites. How can it be done? Surely there is a way if my browser can access all of that information, right? Would you have to put an invisible iFrame into the app and search through it with JS?
To put it in basic terms for a newbie, this is only possible if the website in question has an API, specifically designed to allow outside access. Sometimes they're pretty easy to understand and set up.
Accessing the content of an outside website in a way it wasn't really designed to support has happened, but it's usually what's known as "hacking". It's sometimes easy to do for very basic types of sites, but most sites that request login information forbid it. (Except through aforementioned APIs). The biggest concern is that if someone is already logged in to Twitter on their browser, an outside site of questionable origin could automatically post bad things to your account while you're not even apparently visiting Twitter.
Yes, it's possible.
The best approach is to use ajax (Asynchronous JavaScript and XML) with jsonp (Javascript Object Notation with Padding) datatype.
To use this method the server you are going to connect should be expecting the request so it can response with jsonp (it's just a json data wrapped by a callback function you defined when you make the request).
The process:
1) Your code make an ajax request to the other server adding a callback function to the url. It's very commom to use "callback" param name, but the server can define the variable name it prefers.
http://other-server-url.com/?callback=myFunction
A good and easy approach here is to use jQuery. If you define dataType:"jsonp" in your ajax call, jQuery handles the process of appending the callback and execute the right function when you get the response. It's a good idea to take a look at jQuery's ajax docs and read a little about jsonp cross domain requests.
$.ajax({
type: "POST",
dataType:"jsonp",
url: "http://other-server.com/",
data: { name: "John", location: "Boston" }
}).done(function( msg ) { // this function will be executed when you get the response
alert( "Data Saved: " + msg );
});
this jQuery method only works if the param name is callback. If it isn't, you should handle by your own, or take a deeper look at documentation to know how to do it with jQuery.
2) The server should be waiting for these "callback" param and response your request with a jsonp data format. It's just json data format wrapped by the function you passed as the callback. Like this:
myFunction({ json-data });
3) When you get the response, the myFunction function will be executed automatically, with the json data as the parameter:
function myFunction(myData) {
console.log(myData); // this will log the data on the browser console
}
I hope I have helped. Good coding.
I've been stumped on this for a while. I've successfully created a MediaWiki API extension from which I'm able to extract data using an API url, but now I want to go the other way. I want to use JS to send a simple bit of data to the server for storage in a session variable (in PHP). I've experimented with something like the following:
$.ajax({
// start POST request
type: "POST",
// url to which the request is sent
url: "/",
// data to the server
data: { myvariable: 0 },
// Type of data
dataType: 'json',
// Funciton to be called if the request succeeds
success: function( data ){
console.log("POST successful with " + data);
}
})
What I don't fundamentally get is how to "pick up" the POSTed data in PHP. In my research, I came upon something saying I should look for $_POST['myvariable'] in PHP. Yet I'm not sure how or where I'd create something that would listen for such a POST from JS. It seems to me the easiest solution to this would be if I could write a method onto my API extension that simply assigns the value of the myvariable that's POSTed to the session variable whenever that thing is POSTed. I've written this method already, in fact, but it's unclear to me how I'd instruct AJAX to invoke it in PHP. I've also read that this type of thing may not be advisable for security reasons.
I've seen advice elsewhere suggesting I should do something in JS like:
var api = new mw.Api();
...and then use the Api object's methods to execute Ajax GET and POST requests. Well, I tried creating an instance of this object, and it throws errors on the console that say it's not a recognized function or something of that nature.
I'm rather new at all this, but I'm at my wit's end trying to figure out something that in theory ought to be very simple. Any suggestions?
this is a interesting problem.
i am doing an asynchronous ajax put
return $.ajax({
url: url,
type: 'PUT',
contentType: 'application/json; charset=utf-8',
async: true, // default
success: function (result, textStatus, xhr) {...}
this works as expected, unless a user does a put before previous call returns (even though it's async, the call does take .5 second to complete)
if a user presses the button a few times (executing multiple puts) the following happens:
i see only one server call in fiddler
success gets fired for every click
all callbacks get the same new row ID (returned by the server)
this leads me to inevitable conclusion that the first server callback triggers all outstanding callbacks..
i could disable the button until the callback returns, but is it possible to handle multiple outstanding calls? is this a browser limitation? best way to handle this?
UPDATE
as a test i switched to using POST instead of PUT: adjusted type: 'POST' on JS side, and [HttpPost] on web api (server side).
the behavior did not change.
UPDATE
looking at posts like this one.. this really should work. i don't see any specific reason why the rest of concurrent requests are not not making it out to the server.
Shouldn't PUT requests be idempotent? That is, submitting multiple requests should generate the same response? If so, the code may simply be trying to coalesce your identical PUT requests since they should all end up with the same result. If you're incrementing some ID for every post (i.e. changing server state) then you should be using POST instead of PUT.
This may not fix your issue; it's just a thought.
You can't wait for an async callback in javascript. You have to restructure your code to do all future work based on the async response from the actual callback.
If you need to make multiple consecutive ajax calls, then you issue the first one and in the success handler or response handler for the first ajax call, you issue the second ajax call and in the response handler for the second one, you carry out whatever you want to do with the data
Ok, after an whole day trying to get this to work I just don't seem to know what's the deal with this, so here it goes:
I have a WebService hosted locally by now (http://localhost:15021/Service1.svc/[whatever_method]) and an HTML Page on a different file.
FYI, both WebService and HTML Page will get hosted on different servers.
I'm trying to get some info off the WebService to the HTML Page by the onload=load() method in the HTML Page.
My JavaScript code is:
function load() {
alert("Loading...");
$.ajax({
url: 'http://localhost:15021/Service1.svc/getAllNoticias',
type:'GET',
dataType: 'jsonp',
jsonp: 'loadNews_callBack'
});
}
function loadNews_callBack(result){
alert(result.data);
}
Additionally, the JSONP is loaded on the Page with an OK (200) status (As you can see here) which should (I guess) call the callback function, but it isn't.
What can I do to get around this? I already change the request parameters 500 times (e.g., added "?callback=? to the url, with or without jsonp attribute, etc...)
Any help would be great,
Thanks in Advance
Check the actual response text to verify that the response is correctly being wrapped by the callback function. It is possible that your service is not setup correctly to handle JSONP so it simply responding with JSON. It will still come back as 200, but fail to execute.
loadNews_callBack([json...])
vs
[json...]
See this question as reference on how to go about updating your service:
ASP.net MVC returning JSONP
I've written some HTML/Javascript that sits on a third-party server for security reasons. This page performs a javascript post to another page on the same site. However, instead of responding with useful data, it instead wants to perform a redirect (if you would post via a normal HTML form to this page, it would redirect your browser). How can I process this process? I basically want to be able to extract the url's query parameters that it is trying to redirect with (and then put this link into a hidden form field).
Here is my basic ajax post...
$.ajax({
url: '/someurl/idontcontrol',
data: serialized_form_data,
async: false,
type: 'POST',
success: function(data, textStatus, x) {
alert(x);
alert(x.getAllResponseHeaders());
return false;
$('#redirect_link').val(WHAT_DO_I_PUT_HERE);
}
});
Note that the URL I am posting to is not one that I control, so I have no power over what it returns.
UPDATE: When I use the above alerts, I receive "[object XMLHttpRequest]" and "null". I'm monitoring the headers with a Firefox plugin and they seem be coming back as expected, but I can't seem to access them via javascript (I've also tried x.getResponseHeader('Location'), but that and all other calls to getResponseHeader return empty).
ALSO: I don't know if it matters, but the status code is 302 (as opposed to 301 or 303).
Thanks!
According to the jQuery Documentation the success method can take a third argument which is the XMLHttpRequest object.
According to Mozilla's XMLHttpRequest page, this object should have a "status" property. If you check the value of this property, and it is a redirect code, such as 301 (permanent redirect) or 303 (temporary redirect) it is known the processing page is trying to perform a redirect. The "statusText" property should be able to be used to determine the location it is trying to redirect you to.
If you know it is trying to redirect, you can then re-post the data through Ajax to the new URL.
The strange thing is though, when researching this, stumbled across this page that indicates the XMLHttpRequest object should follow redirects (see the comments). So it seems like this would be a non-issue.
Unless the processing page is using an HTML meta redirect (like below) to do the redirection. In that case, I'm not sure what could be done - maybe try to parse the returned HTML for meta tags and see if any of them are attempting a redirect.
<meta http-equiv="refresh" content="0;url=http://www.example.com/some-redirected-page">
You can't get the full HTTP headers from an AJAX call in JQUery, so you can't process the redirect in this way.
However with a raw javascript request you do have access to the XMLHttpRequest getAllResponseHeaders() method which will allow you to process the redirect (this function for single headers).
Sorry, not directly an answer to your question, but I'm sure it's possible with jQuery too as it's quite simple with Prototype.
// Warning: this is Prototype, not jQuery ;-)
//...
onComplete: function(response) {
var refresh = response.getResponseHeader("Refresh");
var whatever = response.getResponseHeader("Whatever");
}
//...