Nate Weiner

This is an old archived post from my former blog The Idea Shower. It's where I cataloged my product explorations and releases, one of which ultimately became Pocket.

This post was published back in 2009. It may not function as originally intended or may be missing images.

How to Make Simple Cross-Domain Ajax Requests With Responses

June 24, 2009

For Read It Later for the iPhone, I built a 'Tap to Save' bookmarklet for Mobile Safari.  When using Tap to Save, instead of opening a link when clicked, the link is saved to a user's reading list.  This makes it easy to save a few links from a web page without having to open each one individually.

The problem I came across however was I could not do an ajax request to send the link to the Read It Later server because cross-domain browser restrictions.

I could use an iframe to send the request, but again because of cross-domain issues, I would not be able to retrieve a response from inside of it.  After the request was sent, there were 3 possible outcomes: Success, the user needs to login, or there was a problem saving.

The method that eventually dawned on me is rather hackish, but it works none-the-less.  It provides a way to send a request to any domain and get a basic response.

The solution: Images are not subject to cross domain restrictions.  So load an 'image' with a get string that hits a script on the server and then returns an different sized image per possible outcome.

If that makes absolutely no sense, let me try to illustrate with an example that provides a response with two options: success/failure.

Starting the Request: (Javascript: Client Side)

// Load an image pointing to your script ajaxImg = new Image(); ajaxImg .src = 'http://myserver.com/script.php?myvariables=1&foo=bar'; document.body.appendChild(ajaxImg);

// Start a timer to check if the image has loaded ajaxTimer = setInterval('isImageLoaded()', 250);

Handling the Request (Server Side):

The image is now loading this script:

<?php

/* ... do your request processing here ... */

// Based on the result of the script, we either return a // 1px wide image (in the case of success) or // 2px wide image (in the case of failure) // you'll need to create these images yourself

if ($success) { $file = file_get_contents( '1x1.gif' ); } else { $file = file_get_contents( '2x1.gif' ); }

// output the image $length = strlen($file); header('Last-Modified: '.date('r')); header('Accept-Ranges: bytes'); header('Content-Length: '.$length); header('Content-Type: image/gif'); print($file);

?>

Handling the Response: (Javascript: Client Side)

Back on the javascript side of things, we have our ajaxTimer checking to see if the image is loaded. Once the image loads, we'll check the width.

function isImageLoaded() { if (ajaxImg.complete) {

     var w = ajaxImg.width;
     if (w == 1) {
          alert('Success!');
     } else if (w == 2) {
         alert('Failed!');
     }

     // Hide the image (even though you probably won't see it
    ajaxImg.style.display = 'none';

    // Stop the timer
    clearInterval(ajaxTimer);

 }

}

Simple Works Best

As you can see, this works well if you only have a few possible outcomes of the transaction or if you do not need to return a literal response like generated markup.

IE Woes

Surprisingly, this DOES work in IE6 and IE7, however there is a little bit of extra work. The url of the request you load into the src of the image has to have .gif in it. For example: 'script.php' won't work, but 'script.gif' will. So to make this work you'll need to add an Htaccess rewrite rule to redirect the script.gif to your script.php file.

RewriteRule ^script.gif$ script.php [QSA=%{QUERY_STRING}]