Proxy Servlet for AJAX requests to multiple, remote servers

5

AJAX is hot, great and will make the world a better place. We all know that. However, AJAX has some limitations. AJAX is about making additional HttpRequests from the browser once a ‘normal’ request has been satisfied and an HTML document is loaded. Once the initial load is complete, the browser may fire additional requests for resources such as Images, CSS documents and JavaScript libraries. In addition, we can program even more additional requests: the AJAX-requests. Using AJAX we can asynchronuously, in the background, retrieve additional data and content to further enrich, flesh out and embellish our page. These resources can be simlpe text, XML, WebService replies, full blown (X)HTML or basically any character based content that HttpRequests may return.

The one BIG limitation with browsers and AJAX is that, in general, the AJAX requests must be to the same server that server the original HTML document. So your page cannot fire AJAX requests. That means that if you want to use additional content that is not server by your own web server, you have a problem. Invoking a remote WebService to return the weather conditions, getting an RSS-feed with headlines, scraping HTML content from another website: it will not fly. A typical error to run into: uncaught exception: Permission denied to call method XMLHttpRequest.open

So what can you do if you really want to use content from other origins – which is quite likely by the way? Basically there seem to be a few options, some of which are limited to specific browsers:....

  • Digitally sign your scripts. In Firefox you can apply a digital signature to your script and those scripts will then be considered "trusted" by the browser. Firefox will then let you make XMLHttpRequests to any domain. However, no other browsers support script signing at this time, so this solution is of limited use. See: Signed Scripts in Mozilla
  • Use JSON and dynamic <script> tags instead of XML and XMLHttpRequest. You can get around the browser security problem altogether by making your web services request directly inside a <script> tag.
  • Use an alternative XmlHttpRequestAPI based on Greasemonkey’s XMLHttpRequest API, which is more powerful than that available to web pages. It bypasses the same origin policy, thus allowing user scripts to truly compose and remix websites. See: XMLHttpRequest – Security Bypass. Note: by-passing security is perhaps not such a great idea…
  • Use a proxy do make the requests for you: if you cannot make the AJAX requests to remote sites because all requests have to go to the orginal site that served the HTML document, than we should make our AJAX request to that server, to a proxy component that reroutes the request to where we want it to go and returns the results to us in the client! This proxy can be any server side object – PHP, Java Servlet, Perl or Python – that can receive our AJAX request, turn it into a remote request, receive the response from the remote site and pass that response back to the client. The Resources have a link to description of PHP proxy.

Using a proxy to pass through remote requests 

The picture shows the setup, where in this case the AJAX request is targeted at one of the Yahoo! WebServices. 

In this article we will develop a Servlet based Proxy to handle our AJAX requests. Thus, we should be able to develop an HTML document that uses AJAX requests to plugin content from remote sources, something that normal AJAX would not allow.

Developing the Proxy Servlet

What we need is simple servlet that is called by the client. The client should provide in its request the real URL that the proxy should invoke on its behalf. It should also send along all parameters that the proxy should include in the remote call. I started out with the excellent article: HttpProxyServlet version 1.1. Since that code is distributed under a commercial license, I AM NOT ALLOWED TO DECOMPILE THAT CODE (which is what I did in an earlier version of this article). While I am looking for an alternative implementation, this article is currently incomplete.

..

This Servlet is configured in web.xml as follows:

&lt;?xml version = '1.0' encoding = 'windows-1252'?&gt;
&lt;!DOCTYPE web-app PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot; &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot;&gt;
&lt;web-app&gt;
  &lt;servlet&gt;
    &lt;servlet-name&gt;HttpProxy&lt;/servlet-name&gt;
    &lt;servlet-class&gt;nl.amis.proxy.HttpProxyServlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;HttpProxy&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/proxy&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
  &lt;mime-mapping&gt;
    &lt;extension&gt;html&lt;/extension&gt;
    &lt;mime-type&gt;text/html&lt;/mime-type&gt;
  &lt;/mime-mapping&gt;
  &lt;mime-mapping&gt;
    &lt;extension&gt;txt&lt;/extension&gt;
    &lt;mime-type&gt;text/plain&lt;/mime-type&gt;
  &lt;/mime-mapping&gt;
&lt;/web-app&gt;&nbsp;

You can invoke the HttpProxy from the browser using a simple URL like: http://yourhost:port/webapp/proxy?remotehost=www.theserverside.com/index.tss. The result is that the servlet will send a request to the URL passed in in the remotehost parameter and will return the response it received to the browser.

If we can have browser make explicit calls to this servlet, we can also make implicit calls in the shape of AJAX-requests:

  function loadXMLDoc(url) {
    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
        req.onreadystatechange = processReqChange;
        req.open(&quot;GET&quot;, &quot;proxy?remotehost=&quot;+url, true); // the third parameter - true - specified ASYNCHRONOUS processing i.e. not waiting for the response!
        req.send(null);
    // branch for IE/Windows ActiveX version
    } else if (window.ActiveXObject) {
        req = new ActiveXObject(&quot;Microsoft.XMLHTTP&quot;);
        if (req) {
            req.onreadystatechange = processReqChange;
            req.open(&quot;GET&quot;, &quot;proxy?remotehost=&quot;+url, true); // the third parameter - true - specified ASYNCHRONOUS processing i.e. not waiting for the response!
            req.send();
        }
    }
  }

This piece of JavaScript is part of the AjaxProxyClient.html; a static document that allows the user to choose some content-provider. When a selection is made, the loadXMLDoc function is called with a specific URL:

          &lt;h3&gt;Sites and RSS Feeds&lt;/h3&gt;
          &lt;SELECT ONCHANGE=&quot;loadXMLDoc(this.options[this.selectedIndex].value);&quot;&gt;
            &lt;OPTION VALUE=&quot;technology.amis.nl/blog/&quot;&gt;AMIS Technology Blog&lt;/OPTION&gt;
            &lt;OPTION VALUE=&quot;news.bbc.co.uk/rss/newsonline_world_edition/front_page/rss091.xml&quot;&gt;BBC World News&lt;/OPTION&gt;
            &lt;OPTION VALUE=&quot;www.theserverside.com/index.tss&quot;&gt;The Server Side&lt;/OPTION&gt;
            &lt;OPTION VALUE=&quot;www.orablogs.com/orablogs/rss.xsql&quot;&gt;OraBlogs&lt;/OPTION&gt;
            &lt;OPTION VALUE=&quot;www.nu.nl&quot;&gt;NU.NL&lt;/OPTION&gt;
          &lt;/SELECT&gt;
&nbsp;

The function makes the Ajax request and when the response is received from the proxy-servlet, it is pasted into the TEXTAREA and the DIV:

 

 

 

When the user selects a different source, a new Ajax Request is sent, possibly to an entirely different server – cross domain and all – and the content when received is displayed in the TEXTAREA and the DIV. Note: the AJAX request itself is not sent to a different server: it is also sent to the proxy servlet; the proxy in turn makes a server side request to an entire different server.

Note: there still seem to be some issues with this solution: some urls seem to cause problems, for example when they are are dynamically redirected. I have also experienced some problems with URLs that did not seem to return a correct content-type. This obviously needs attention when using the proxy servlet for real.

Resources

HOWTO: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls – article on creating a proxy for Web Requests using PHP. Also provides some pointers for alternative solutions

 

 

 

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

5 Comments

  1. Hello I want to create multiple Select components in a JSP Page using AJAX with one or various Servlets.
    But the problem is that not all the options in the First Select have a child associated.

    Please if everyone can help me how can I made it, write the solution.

    Thanks

  2. You may use the component, the non-commercial usage as well as the development are free and it is correct. You did the quote where is come from so it is absolutely ethical, just the decompilation was the wrong action

  3. I sincerely apologize; like I indicated in the article –
    it is no foul intent. I do not benefit in any way from your code and did not want to infringe on your rights in any way. I will immediately remove your code from this article, and find alternative ways for implementing this functionality.

  4. >I started out with the excellent article: HttpProxyServlet version 1.1. I have downloaded and decompiled that >code. Note: while the code is not spectacular, it saved me quite some work. I am not entirely sure whether >decompiling this code is correct. If not, please let me know.

    See http://www.servletsuite.com/license.htm
    So what you are doing is absolutely illegal in all the ways: either business or scientific way.
    way. Please, contact us to clear that matter.