SnTT: Proxyless cross-domain AJAX via DOM scripting
Category show-n-tell thursday
Strictly speaking, AJAX is impossible when spanning domains due to browser restrictions preventing cross-site scripting ("XSS"). Although security issues make this prudent, this does limit our ability to allow web applications to retrieve data from other sites when there is a legitimate need to do so. The standard workaround is to use a proxy to load the remote data: an AJAX request is issued to the server, instructing it which data to pull; the server retrieves the data and sends it back to the browser. There are two drawbacks to this approach:
function loadODJ() {
var headTag = document.getElementsByTagName('head')[0];
var scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = arguments[0]; // the script file's URL is passed to the function
headTag.appendChild(scriptTag);
}
On the example page included above, the first example attempts to use XMLHttpRequest to load an HTML page on timtripcony.net from a page on timtripcony.com. Both domains reside on the same server, but the browser doesn't know that; it sees two different domains and blocks the request.
When a script tag is added to the DOM, its source is loaded and then executed immediately. This allows us some intriguing options for dealing with remote data. The second example appends a script tag that points to a script file that includes a single alert statement. The alert is executed rapidly, because there's very little data for the browser to download, and it doesn't have to tell the server to load the data and then wait for it to do so.
The third example is a bit more interesting: a variable named loadCount has already been declared in the header of the example page, initialized with a value of 0. The script file that this example loads increments this variable's value and alerts the result. Script loaded in this way becomes part of the page's global execution scope, so it can access existing global variables and functions... and define new ones, which can be referenced later by other code within the page or in other dynamically loaded script.
The final example is the most interactive, and comes closest to demonstrating a real-world use case. When the script is loaded, a query string parameter is included in the script's URL based on a value selected from a drop-down list. The remote script is dynamically generated: the query string parameter becomes the key for a DbLookup. An additional parameter specifies which global function to use as a callback; once the DbLookup is complete, the result data is passed to the callback function, which alerts the result. In Domino this dynamic script generation is easy to do, because design elements like agents, pages, and forms can masquerade as .js files as long as their Content-Type is set correctly. One scenario in which this kind of integration would be useful is when deploying a web application that will be used in-house by numerous organizations but must still be able to access centralized data. This presents an opportunity to provide a dynamic API: no matter which servers host the application, they come to the central server to retrieve the current data.
To sum up, DOM scripting allows us to overcome the cross-domain limitation of XMLHttpRequest, but requires that we have at least some control over both domains involved. Enjoy.
Strictly speaking, AJAX is impossible when spanning domains due to browser restrictions preventing cross-site scripting ("XSS"). Although security issues make this prudent, this does limit our ability to allow web applications to retrieve data from other sites when there is a legitimate need to do so. The standard workaround is to use a proxy to load the remote data: an AJAX request is issued to the server, instructing it which data to pull; the server retrieves the data and sends it back to the browser. There are two drawbacks to this approach:
- Data retrieval is often slower. The obvious reason for this is that the browser has to wait for the server to retrieve the data instead of just retrieving it directly. But there's another performance implication: instead of simply serving its own data, it's also loading remote data for all users requesting it.
- Firewall restrictions on servers - particularly intranet servers - are often tighter than those placed on clients. Although the user may have access to the destination domain, the server may not, in which case the lookup will simply fail.
function loadODJ() {
var headTag = document.getElementsByTagName('head')[0];
var scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = arguments[0]; // the script file's URL is passed to the function
headTag.appendChild(scriptTag);
}
On the example page included above, the first example attempts to use XMLHttpRequest to load an HTML page on timtripcony.net from a page on timtripcony.com. Both domains reside on the same server, but the browser doesn't know that; it sees two different domains and blocks the request.
When a script tag is added to the DOM, its source is loaded and then executed immediately. This allows us some intriguing options for dealing with remote data. The second example appends a script tag that points to a script file that includes a single alert statement. The alert is executed rapidly, because there's very little data for the browser to download, and it doesn't have to tell the server to load the data and then wait for it to do so.
The third example is a bit more interesting: a variable named loadCount has already been declared in the header of the example page, initialized with a value of 0. The script file that this example loads increments this variable's value and alerts the result. Script loaded in this way becomes part of the page's global execution scope, so it can access existing global variables and functions... and define new ones, which can be referenced later by other code within the page or in other dynamically loaded script.
The final example is the most interactive, and comes closest to demonstrating a real-world use case. When the script is loaded, a query string parameter is included in the script's URL based on a value selected from a drop-down list. The remote script is dynamically generated: the query string parameter becomes the key for a DbLookup. An additional parameter specifies which global function to use as a callback; once the DbLookup is complete, the result data is passed to the callback function, which alerts the result. In Domino this dynamic script generation is easy to do, because design elements like agents, pages, and forms can masquerade as .js files as long as their Content-Type is set correctly. One scenario in which this kind of integration would be useful is when deploying a web application that will be used in-house by numerous organizations but must still be able to access centralized data. This presents an opportunity to provide a dynamic API: no matter which servers host the application, they come to the central server to retrieve the current data.
To sum up, DOM scripting allows us to overcome the cross-domain limitation of XMLHttpRequest, but requires that we have at least some control over both domains involved. Enjoy.








Comments
In the examples on the first button I get an error: 'Ajax' is undefined..
Posted by Patrick Kwinten At 02:55:04 On 02/02/2007 | - Website - |
Most requests I've had for Ajax stuff involved data from other domains.
I'll check this out asap
Posted by Vince Schuurman At 12:31:23 On 02/01/2007 | - Website - |