- 2.1 XMLHttpRequest Overview
- 2.2 Cross-Browser XMLHttpRequest
- 2.3 Sending Asynchronous Requests
- 2.4 AJAX Without XMLHttpRequest
- 2.5 Fallback Option 1: Sending a Request Using an IFrame
- 2.6 Fallback Option 2: Sending a Request Using a Cookie
- 2.7 Summary
2.6 Fallback Option 2: Sending a Request Using a Cookie
You can transfer data to your server using cookies, but any implementation using them will be severely limited. Cookies have a maximum size of 4k, and each domain can set only 20 of them, which means that each request is going to be size-limited. Cookie-based AJAX is most useful when your site is designed for it, because its limitations make it hard to use it as a fallback. The basic functionality is provided by setting a cookie, loading an image, and then polling on an interval while waiting for the response to appear. The implementation is simple; to do something besides alerting the contents of the result, you just set your own custom onComplete event handler. An example where the server returns the input and the number of times it has been called is shown in Listings 2-7 and 2-8. The example's JavaScript is shown in Listing 2-7, and the PHP code, which reads the cookie and then sets a response, is shown in Listing 2-8.
Listing 2-7. Cookie-Powered AJAX
1 <html> 2 <head> 3 <title>Cookie Test</title> 4 5 <script type="text/javascript"> 6 function CookieRequest() { } 7 CookieRequest.prototype = { 8 interval: 500, 9 attempts: 5, 10 attemptCounter: 0, 11 call: function(url,payload) { 12 var d = new Date(); 13 var i = new Image(); 14 this.setCookie('CR',payload); 15 i.src = url + '?u=' + d.getTime(); 16 var self = this; 17 this.timerId = setTimeout(function() 18 { self.read(); }, this.interval); 19 }, 20 read: function() { 21 this.attemptCounter++; 22 // check for data 23 var data = this.getCookie('CR'); 24 if (data != false) { 25 this.attemptCounter = 0; 26 this.onComplete(data); 27 return true; 28 } 29 30 // check for error 31 if (this.attemptCounter > this.attempts) { 32 this.onError(); 33 } else { 34 var self = this; 35 this.timerId = setTimeout(function() { self.read(); }, 36 this.interval); 37 } 38 }, 39 onComplete: function(result) { 40 alert(result) 41 }, 42 onError: function() { 43 alert('Request timed out'); 44 }, 45 setCookie: function(name, value, expires) { 46 document.cookie = name + "=" + escape(value) + 47 ((expires) ? "; expires=" + 48 expires.toGMTString() : ""); 49 }, 50 getCookie: function(name) { 51 var docCookie = document.cookie.split("; "); 52 for (var i=0; i < docCookie.length; i++){ 53 var piece = docCookie[i].split("="); 54 if (piece[0] == name) { 55 return unescape(String(piece[1]). replace(/\+/g, " ")); 56 } 57 } 58 return false; 59 } 60 } 61 function test() { 62 var cr = new CookieRequest(); 63 cr.call('cookie.php','Some Example Data'); 64 } 65 </script> 66 </head> 67 <body> 68 <a href='javascript:test()'>Test</a> 69 </body>
In Listing 2-7, the cookie-powered AJAX functionality is wrapped inside the JavaScript class CookieRequest. Requests to the server are made with the call method (lines 11–19). The call method takes a URL to which to send the request. It also takes a payload (the content we want to send to the server), which is sent in the request cookie. The method then uses the setCookie method to set a cookie named CR (line 14); it then creates a new Image object and sets its src to the requested URL (line 15). The method finishes by starting a timer, which runs the read method every 500 milliseconds.
The read method (lines 20–38) checks for the presence of the CR cookie (lines 23–24). If it exists, the data in it is passed to the onComplete method (line 26). If the data isn't present, we check for errors; this is done by comparing the number of checks we've completed against the max checks set in the attempts property (line 31). If there is an error, the onError method is called (line 32). If no error is present, we start another timer to do the next check (lines 34–35).
Lines 39–44 contain methods that you'll override when using the class. The onComplete method is called when data is successfully loaded. This is the equivalent of the callback property in the HttpClient class. The onError method is called if the request doesn't complete successfully; of course, you could leave this as an alert, but, in most cases, you'll want to provide a more understandable error message to your users or even retry the request.
The CookieRequest class also contains helper methods for dealing with getting and setting cookies. setCookie (lines 45–49) works by setting the value of document.cookie to a urlencoded string in the format of cookie name=value. getCookie (lines 50–59) works by splitting document.cookie into one part for each cookie (the cookies are separated by ";") and then looping over these parts looking for a cookie with the specified name. If a matching name is found, the value is returned; otherwise, false is returned.
The PHP page that is used with Listing 2-7 is shown in Listing 2-8. It is used as the URL in the call method and processes the payload that is set; it then sets a response for read to grab.
Listing 2-8. PHP Server Page for Handling a Cookie AJAX Request
1 <?php 2 session_start(); 3 if (!isset($_SESSION['i'])) { 4 $_SESSION['i'] = 0; 5 } 6 if (isset($_COOKIE['CR'])) { 7 $_SESSION['i']++; 8 setcookie('CR','Server Responds: '.$_SESSION['i'].', 9 '.$_COOKIE['CR']); 10 } 11 ?>
This PHP code provides the basic functionality needed to interact with cookie-based AJAX requests. It uses PHP sessions to store a counter and increments it as each request is made. As you extend this code, you could use different PHP pages to decide which action to perform, or you could include that information in the cookie that is sent from the client. Lines 2–5 handle basic session setup, setting the counter to 0 if this is the first call. Lines 6–10 handle the checking of the client cookie and the sending of the response. This is done by setting a cookie that then will be sent with the response (line 8–9). If you want to handle large server responses, you would need to include code to split the data among multiple cookies.