A Short Guide to AJAX programming

From Wikiid
Revision as of 09:15, 10 March 2011 by SteveBaker (Talk | contribs) (POST)

Jump to: navigation, search

First let's review how HTTP works to get web pages into the browser:

HTTP

When the web browser wants a page from a website, the following sequence ensues:

  1. The browser sends an HTTP (HyperText Transport Protocol) command over the Internet to the server containing the URL of the web page - and then sits around waiting for a response.
  2. On the server, a program called "httpd" (the HTTP daemon) is "awoken" by the operating system and handed the URL. Most websites run "Apache" as their HTTP daemon - but there are others form Microsoft and elsewhere that work kinda similarly. I'm going to talk about Apache because that's what we use.
  3. What Apache does next depends on the filename extension:
    • If there is no filename (eg "http://tubagames.net") then it changes the filename internally to "index.html" (or if that doesn't exist: "index.php").
    • Most of the time (eg with an ".html" or ".css" or ".gif"/".png"/".jpg" file), Apache finds the file, sticks a special "MIME header" on to the top of it - and sends it back to browser.
    • If the URL that's requested has the ".php" extension, then Apache grabs the file - hands it to the PHP interpreter, which runs the program, which generates some output (including a "MIME header") that gets handed back to Apache...which passes it on to the browser. The PHP code essentially "prints out" the web page and exits...but more complicated things are also possible (such as checking for cookies and running other Linux programs on the server).
    • If the URL is a ".cgi" file and is stored in a certain special "cgi-bin" directory then Apache runs it as a regular Linux program (probably written in C++ - but could be something else). Whatever the CGI program writes to the output (with 'printf' or 'cout <<...'). Apache takes whatever it outputs and sends it to the client. Because we don't want any random idiot with a browser to be able to run any program whatever on our server, CGI program executable have to be kept in a certain approved directory (which in our case is called "cgi-bin"). Apache knows where this directory is - and refuses to run programs from anyplace else.
  4. When the browser gets the resulting data - be it a file, results from PHP or results from CGI - it looks for the "MIME header" - and either displays it, or sets the style or whatever - depending on what the header tells it to do.

The "MIME header" is pretty important because that's how the browser knows what to do with the file.

When Apache serves up a simple file (eg an HTML file or an image), it sticks a MIME header on it that tells the browser what type it is based on the file extension. When you run PHP programs, the header is added automatically by PHP - but in CGI programs, you have to be sure to write the header out yourself.

For an HTML file, the header is just:

  Content-Type:text/html

...and the browser knows what to do with text/html files...it displays them. The "text/html" part is called the "MIME type"...which actually comes from email protocols...but that's another story. Aside from the standard MIME types like "text/html" and "image/jpeg", you can tell your browser to do things like running special plugins for particular MIME types. That's how the Flash plugin gets invoked when Apache sends the browser a ".swf" file. There are special header types for CSS files and other stuff like that. You'll notice that (for example) all of our ".php"-ized CSS files start with something like:

 <?php   header("Content-type: text/css");  ?>

...which tells PHP to emit a header with the MIME type "text/css" rather than the usual "text/html" so that the browser knows that this ".php" file is really a style sheet. A regular ".css" file has the same MIME header - but Apache generates it automatically because of the filename extension. To pick another example, our Mozilla app-store manifests start with:

 <?php   header("Content-Type: application/x-web-app-manifest+json");   ?>

...which generates the MIME header that the App Store expects.

Parameters: GET and POST

GET

When you go to (say) Google and type in something into an HTML form, the resulting HTTP request contains an extended URL which has some extra "stuff" on the end (these are called "GET parameters"):

  http://www.google.com/index.html#q=helloworld

...everything after the "#" is a set of parameters separated by the "&" character. The example above sets the "q" (query? question?) parameter to the value "helloworld" - which Google obediently searches for. If you really do a Google search for "helloworld", it'll produce this kind of mess:

 http://www.google.com/#sclient=psy&hl=en&q=helloworld&aq=f&aqi=&aql=&oq=&pbx=1&bav=on.2,or.&fp=bfd1057040a6822d

Which sets a BUNCH of parameters:

 sclient=psy
 hl=en                <== Searching in English
 q=helloworld         <== We understand this one!
 aq=f
 aqi=
 aql=
 oq=
 pbx=1
 bav=on.2,or.
 fp=bfd1057040a6822d

...who knows what all of those mean?!)

This data really only means something for PHP and CGI URL's. PHP and C++ "CGI" programs can read those parameters and do something different depending on what they are...Google clearly uses the value in the "q" parameter to determine what to search for.

This approach to sending data is called the "GET" method (I don't know why) and it's considered kinda old-fashioned.

In C++, the "GET" parameters are passed to the program on the command line - so you have to parse argc and argv to read them.

In PHP, there is an array called "$_GET[]" that's indexed by the parameter name and contains whatever parameters are passed this way. So if you were writing your own Google clone using PHP, you could say:

 if ( isset ( $_GET ['q'] ) ) 
 {
   $result = searchTheWebFor ( $_GET['q'] ) ;
   echo "Found these results:<br>" ;
   echo $result ;
 }
 else
   echo "Error: No search terms entered?" ;

This is OK so long as there isn't much data to transmit - but there is a fairly small upper limit on the length of a URL - so you can't send more than a few hundred bytes to the server using the GET method.

POST

The "POST" method is more suited to PHP and CGI and you can send an almost unlimited amount of data up to the server. That's how you can do things like uploading files or big chunks of text (such as I'm doing when I sent this page to the Wiki).

In the POST method, the URL is just the name of the program you want to talk to. The data can be any "MIME type"...but it's usually ASCII text. For example, this HTML snippey "posts" data to a PHP program running on the server:

 <form action="http://example.com/echo.php" method="post">
 Type something: <input type="text" name="something" />
 <input type="submit" />
 </form>

In PHP, everything works exactly the same way as with "GET" except that the array is called "$_POST[]" - so you could create a web page called "echo.php" containing:

 <H1>You typed:</H1>
 <?php
   echo $_POST["something"] ;
 ?>

...and the result would be that you type into the form in the first web page, hit the "submit" button and whatever you wrote would appear underneath the 'H1' heading in the web page.

To do the same thing in a C++ CGI program takes a bit more work:

 #include <stdio.h>
 #include <stdlib.h>
 int main ( int argc, char **argv )
 {
   char buffer [ 1024 ] = { 0 } ;
   fread ( buffer, 1024, 1, stdin ) ;
   printf ( "Content-Type:text/html\n\n" ) ;  // IMPORTANT: DON'T CHANGE THIS LINE!
   printf ( "  <H1>You typed:</H1>" ) ;
   printf ( "     %s\n", buffer ) ;
 }

...if you call this (let's say) "echo.cpp", compile it on the server, place it into the "cgi-bin" directory with a ".cgi" file: "cgi-bin/echo.cgi"...then you can use this form to invoke it:

 <form action="http://example.com/cgi-bin/echo.cgi" method="post">
 Type something: <input type="text" name="something" />
 <input type="submit" />
 </form>

Now you can type something into that text box - and whatever you type will go up to the server, the echo.cgi program will be run, it reads our input and prints out an HTML document with that text inside. It's really the same deal as the PHP program except that the PHP language is optimised to do this and C++ wasn't. Hence you have to generate the MIME type explicitly in C++, but it defaults automatically to HTML when you write in PHP.

AJAX

So...finally...we're ready to talk about the "AJAX" thing. This uses the "POST" method to send data from the browser to the server and back again...exactly like we did above. But the difference here is that JavaScript code sends the command to the server - and JavaScript reads the result instead of the web browser itself.

Because JavaScript programs have to run quickly and then end - they can't hang around waiting for the round trip to the server. So you set up an "event" for the browser to call when the results come back.

First, create a global variable to hold the transaction information:

 var http_request = new XMLHttpRequest () ;

...the original idea was to use this technique to fetch XML documents - but you can actually get any kind of data this way.

Then, you need to define a function that'll be called when the results arrive. Let's call it "updateFunc"...and we'll talk about what it does in just a moment.

When you want to talk to the server:

 function sendToServer ( myData )
 {
   http_request.onreadystatechange = updataFunc ;
   http_request.open ( "POST", "http:whatever.com/cgi-bin/echo.cgi", true );
   http_request.setRequestHeader( "Content-type","application/x-www-form-urlencoded");
   http_request.send ( myData ) ;
 }

...notice the name of our results gathering function "updateData" being set as the "onreadystatechange" event. Note that the full URL is passed on the second line, some "Content-type" header for the message (don't change this!) - and finally, we pass in the data - which actually causes the message to be sent.

The "updateFunc" function is called when the results are returned:

 function updateFunc ()
 {
   var ready = http_request . readyState ; if ( ready !=   4 ) return ;
   var stat  = http_request . status     ; if ( stat  != 200 ) return ;
   var result = http_request . responseText ;
   // ...do something with the result...
   alert ( result ) ;  // Pop up an alert box with the results in it.
 }

The system may call your "net_update" function several times - indicating various stages of progress before you actually have the message available. Hence the first two lines of the function check various status stuff and just return if there is a problem or if the message didn't actually arrive yet. When we finally get our answer, the "result" variable will be a string containing whatever the CGI or PHP program sent you.