Several new technologies are coming out for accessing resources from other sites. IE8 will include the XDomainRequest and the W3C is finishing the access control specification for enabling cross-site access for XMLHttpRequest, which will probably be implemented in next major release of all browsers, including Firefox. However, it will certainly take a long time for these new technologies to become pervasive enough to use them reliably and exclusively. Is there any way to leverage this technology immediately when these browsers are released? Yes! With Dojo’s new XHR plugin system, you can start making cross-site requests right away, using the new technologies when available, and a proxy server as a fallback, all while using the familiar dojo.xhr* methods. Your source code can still use this simple API while the registry can handle choosing the appropriate underlying transports for the situation.

Using the XHR Plugin Registry

Suppose we need to securely access a web service from othersite.com. This server can easily support the W3C Access Control specification by including this header:

Access-Control: allow <*>

Now we can use cross-site XHR and XDomainRequest handling for XHR calls to this destination by simply calling:

dojox.io.xhrPlugins.addCrossSiteXhr("http://othersite.com/");

Now on IE8, if you call:

dojo.xhrGet({url:"http://othersite.com/data"})

This request can be handled directly in the browser with XDomainRequest. Similarly in other browsers that implement cross-site capability in the XmlHttpRequest API, this will result in an XHR call.

You can also use the window.name module as an XHR plugin as well. There is a specific module to make this easy to add, so you can simply call:

dojo.require("dojox.io.xhrWindowNamePlugin");
dojox.io.xhrWindowNamePlugin("http://othersite.com/");

Proxy

These plugins will utilize the browser’s cross-site request capability when available, however, you still need a fallback for older browsers. One of the most common techniques for doing this is with a proxy service. To create a proxy service, you simply need to create a resource (servlet, php file, etc.) that can take a parameter and then make a request from the target site and return the results. Once you have created a proxy service, we can add it as an XHR plugin:

dojox.io.xhrPlugins.addProxy("/proxy?url=");

This handles the remaining use cases. Any request to a foreign URL that can’t be handled by the browser will be sent to the local /proxy URL with the url parameter set to the foreign URL. Now if we call:

var deferred = dojo.xhrGet({url:"http://othersite.com/data"});
or
var deferred = dojo.xhr("GET",{url:"http://othersite.com/data"});

This will be handled directly from the browser (which is faster and more efficient) when possible, and will go to through proxy when the browser can’t handle it. Local XHR calls will still be handled by the normal XMLHttpRequest object. If we call:

var deferred = dojo.xhrGet({url:"/myLocalData"})

There will be no difference in behavior, the registry automatically chooses the original XHR handler for this request. Other handlers could be added to the registry as well. For certain applications and servers, it may be possible to use a JSONP (which is unfortunately not secure) handler or iframe proxy as a substitute cross-site XHR handler.

Security Notes

When using a proxy, there may be certain headers from the original request that can be passed on, but generally you should not pass on cookies, as they may have sensitive information from your site. You should also use proper filtering mechanisms, as blindly routing HTML or scripts can lead to cross-site scripting security holes.

HTTP Adapters

Some applications may rely on certain HTTP level meta-data like headers, methods, and status codes. However, not all transports necessarily have access to the HTTP layer in order to define or access this information. Rather than requiring application logic to be modified to transfer meta-data in alternate way, you can define a convention for converting HTTP meta-data to something that is accessible to the underlying transport at the XHR API level, in order to retain this information. Both addCrossSiteXhr and xhrWindowNamePlugin have an optional second argument that can take a function. This function will be called with the default XHR handler as an argument, and should return a function that will be called for each XHR call. You can build a custom HTTP adapter, or the xhrPlugins module provides a default converter that can easily be used:

dojox.io.xhrWindowNamePlugin("http://othersite.com/",dojox.io.xhrPlugins.fullHttpAdapter);

This adapter will automatically convert the HTTP method to a parameter named http-method in the query string of the request URL. It will also add any defined headers to the query string with an http- prefix. Consequently calling:

dojo.xhr("PUT",{url:"http://othersite.com/page",headers:{"Range":"0-20 bytes"}});

Would result in a request URL:


http://othersite.com/page?http-method=PUT&http-Range=0-20%20bytes

You can even build your own HTTP adapter for custom conversions.

Conclusion

The XHR plugin registry allows you to explicitly define and use different transports that are used in different situations based on browser and server support, while still allowing the call-site syntax to remain a simple call to a dojo.xhr function. All this is done through explicit techniques to avoid magic and surprises. This allows for a clean separation of request triggering and transport definition, allowing transports to evolve for cross-domain loading while not affecting the application logic that relies on requests and can remain agnostic to the underlying transport mechanism. The XHR plugin registry will be available when Dojo 1.2 is released, and is available in the current Dojo nightly builds.