AJAX - Introducing Cross-domain Request (XDR)

With Cross-domain Request ("XDR") in Windows Internet Explorer 8, developers can create cross-site data aggregation scenarios. Similar to the XMLHttpRequest object but with a simpler programming model, this request, called XDomainRequest, is the easiest way to make anonymous requests to third-party sites that support XDR and opt in to making their data available across domains. Three lines of code will have you making basic cross-site requests. This will ensure that data aggregation for public sites such as blogs or other social networking applications will be simple, secure and fast.

This topic contains the following sections.

  • Background
  • API Documentation
  • Code Sample
  • Related topics

Background

Web browsers have a security policy called the same-site origin policy, which blocks Web pages from accessing data from another domain. Web sites often work around this policy by having their server request content from another site's server in the backend, thus circumventing the check within the browser, as shown in the following diagram.

Process for typical mashup site in Internet Explorer 7 and earlier

In Internet Explorer 8, Web pages can simply make a cross-domain data request within the browser by using the new XDomainRequest object instead of a server-to-server request, as shown in the following diagram.

Cross-domain request in Internet Explorer 8

Cross-domain requests require mutual consent between the Web page and the server. You can initiate a cross-domain request in your Web page by creating an XDomainRequest object off the window object and opening a connection to a particular domain. The browser will request data from the domain's server by sending an Origin header with the value of the origin. It will only complete the connection if the server responds with an Access-Control-Allow-Origin header of either * or the exact URL of the requesting page. This behavior is part of the World Wide Web Consortium (W3C)'s Web Application Working Group's draft framework on client-side cross-domain communication that the XDomainRequest object integrates with.

For example, a server's Active Server Pages (ASP) page might include the following response header.

<% Response.AddHeader("Access-Control-Allow-Origin","*") %>

Security Warning: To protect user data, cross-domain requests are anonymous, which means that servers cannot easily find out who is requesting data. As a result, you only want to request and respond with cross-domain data that is not sensitive or personally identifiable.

API Documentation

The following JavaScript code introduces the XDomainRequest object and its events, properties, and methods. The XDomainRequest reference page has more detail than is listed here.

// Creates a new XDR object.
xdr = new XDomainRequest();  

// Indicates there is an error and the request cannot be completed. 
xdr.onerror = alert_error;
                        
// The request has reached its timeout. 
xdr.ontimeout = alert_timeout;
                        
// The object has started returning data.
xdr.onprogress = alert_progress;
                        
// The object is complete. 
xdr.onload = alert_loaded;

// Sets the timeout interval.
xdr.timeout = timeout;

// Gets the content-type header in the request.
var content_type = xdr.contentType;

// Gets the body of the response.
var response = xdr.responseText;
                        
// Creates a connection with a domain's server. 
xdr.open("get", url);
 
// Transmits a data string to the server. 
xdr.send();

// Terminates a pending send.
xdr.abort();

Code Sample

XDR has two components: a client side that makes a request for data to a URL across domains, and a server side that responds with the Access-Control-Allow-Origin header of either * or the exact URL of the requesting page, plus the data, which Windows Internet Explorer then makes available to the requesting domain after performing security checks.

This sample page takes a URL and does a get request. The Read button will call a method to output the response data if you choose to. The first code sample that follows is the requesting page.

Note  To properly demonstrate XDR, you should copy this page to a Web server on a different domain. You may also enable Microsoft Internet Information Services (IIS) on your computer and host it locally from within C:\inetpub\wwwroot. For more information on installing Microsoft Internet Information Services (IIS), search for "IIS" in Help and Support on the Start menu.

<!DOCTYPE html>
<html>

<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta />
<title>Internet Explorer - Cross-domain Request Code Sample</title>

</head>

<body>

<div class="body">
    <h1>Internet Explorer - Cross-domain Request Demo</h1>
    <form>
        <!-- Assign URL and timeout values from their text boxes to variables. -->
        <p>URL:    <input id="input_url" type="text" 
        value="https://samples.msdn.microsoft.com/workshop/samples/author/dhtml/Ajax/xdomain.response.movies.aspx"
        style="width: 700px"></p>
        
        <p>Timeout: <input id="input_timeout" type="text" value="10000"></p>
        <div id="alertdisp" style="display:none; width:500px"; ></div>
        <p><input onclick="req_init()" type="button" value="Get">&nbsp;&nbsp;&nbsp;
        <input onclick="req_abort()" type="button" value="Abort">&nbsp;&nbsp;&nbsp;
        <input onclick="read_data()" type="button" value="Read"></p>
    </form>
    <div id="text_response">
    </div>
</div>
  <script type="text/javascript">
    var xdr;

    function alertDisp(message) {
      var disp = document.getElementById("alertdisp");
      disp.style.display = "block";
      disp.innerHTML = message;
    }

    function read_data() {
      var output = document.getElementById('text_response');
      if (output) {
        // To view the responseText on the page, click the Read button. 
        output.innerText = xdr.responseText;
      }

      // The Read button also displays the content type and length of 
      // response in alerts.  
      alertDisp("Content-type: " + xdr.contentType + "   Length: " + xdr.responseText.length);
      //alertDisp("Length: " + xdr.responseText.length);
    }

    function alert_error() {
      alertDisp("XDR onerror");
    }

    function alert_timeout() {
      alertDisp("XDR ontimeout");
    }

    function alert_loaded() {
      alertDisp("XDR onload" + "\n  Got: " + xdr.responseText);
      //alertDisp("Got: " + xdr.responseText);
    }

    function alert_progress() {
      alertDisp("XDR onprogress" + "  Got: " + xdr.responseText);
      //alertDisp("Got: " + xdr.responseText);
    }

    function req_abort() {
      if (xdr) {
        xdr.abort(); // Abort XDR if the Stop button is pressed. 
      }
    }

    function req_init() {
      var url =
      document.getElementById('input_url').value;
      var timeout =
          document.getElementById('input_timeout').value;
      if (window.XDomainRequest) // Check whether the browser supports XDR. 
      {
        xdr = new XDomainRequest(); // Create a new XDR object.
        if (xdr) {
          // There is an error and the request cannot be completed. 
          // For example, the network is not available.
          xdr.onerror = alert_error;

          // This event is raised when the request reaches its timeout. 
          xdr.ontimeout = alert_timeout;

          // When the object starts returning data, the onprogress event 
          // is raised and the data can be retrieved by using responseText.
          xdr.onprogress = alert_progress;

          // When the object is complete, the onload event is raised and 
          // the responseText ensures the data is available. 
          xdr.onload = alert_loaded;

          xdr.timeout = timeout;

          // The URL is preset in the text area. This is passed in the 
          // open call with a get request.
          xdr.open("get", url);

          // The request is then sent to the server.  
          xdr.send();
        }
        else {
          alertDisp('Failed to create new XDR object.');
        }
      }
      else {
        alertDisp('XDR does not exist.');
      }
    }

    // function to abort a request
    function req_abort() {
      if (xdr) {
        xdr.abort(); // Abort XDR if the Stop button is pressed. 
      }
    }

</script>
</body>

</html>

Click to view sample.

Click the Show Me button to try it out. Note the two fields and the three buttons:

  • The URL field is preset with a URL to which the page will send the get request. The URL for the file is https://samples.msdn.microsoft.com/workshop/samples/author/dhtml/Ajax/xdomain.response.movies.aspx.
  • The Timeout field is preset to a timeout value of 10,000 milliseconds (10 seconds).
  • The Get button sends the get request to the specified URL.
  • The Stop button aborts the get request.
  • The Read button reads the response text and writes it to the page, and then reads and displays both the content type and length.

The second code sample is the target page, which is referred to in the requesting page. In this case, the target page contains a list of movie data.

<% Response.AddHeader("Access-Control-Allow-Origin","*") %>
movieID|movieName|actor|genre
1|Fistful of Dollars|Clint Eastwood
2|Mission Impossible|Tom Cruise|Action
3|Enforcer|Clint Eastwood|Love Story
4|Gauntlet|Clint Eastwood
5|LawnMower Man|John Curtis|Drama
6|The Shining|Jack Nicholson|Drama
7|Dirty Harry|Clint Eastwood|Make my day
8|Two mules for Sister Sarah|Clint Eastwood
9|Hard to Kill|Stephen Segal|Action
10|Top Gun|Tom Cruise|High Intense Action

Web Applications

Client-side Cross-domain Security

Introducing AJAX Navigations

Connectivity Enhancements in Internet Explorer 8