Internet Explorer on Windows and Mozilla provide a method for client side javascript to make HTTP requests. This allows you to make HEAD requests to see when a resource was last modified, or to see if it even exists. It makes your scripting options more flexible allowing for POST requests without having the page change, and opens up the possibility of using PUT, DELETE etc.
Whilst the object is called the XML HTTP Request object it is not limited to being used with XML, it can request or send any type of document.
In Internet Explorer, you create the object using new
ActiveXObject("Msxml2.XMLHTTP")
or new
ActiveXObject("Microsoft.XMLHTTP")
depending on the version of
MSXML installed.
In Mozilla you use new XMLHttpRequest()
This means that you need to show different script to different
browsers, as what works in one, will error in another. The script
below does this, and if it's not supported, the variable is set to
false to allow for appropriate error messages. However, it is not
possible to protect older (non-IE) browsers from erroring on this code
as they do not support try {} catch {}
.
var xmlhttp /*@cc_on @*/ /*@if (@_jscript_version >= 5) try { xmlhttp=new ActiveXObject("Msxml2.XMLHTTP") } catch (e) { try { xmlhttp=new ActiveXObject("Microsoft.XMLHTTP") } catch (E) { xmlhttp=false } } @else xmlhttp=false @end @*/ if (!xmlhttp) { try { xmlhttp = new XMLHttpRequest(); } catch (e) { xmlhttp=false } }
Making a HTTP request is very simple. You tell the XML HTTP request object what sort of HTTP request you want to make and which url you want to request. Provide a function to be called when as the request is being made, and finally what, (if any) information you want sent along in the body of the request.
The following script makes a GET request for the relative url "text.txt" (relative to the calling page) It provides the function, which checks the readyState
property each time it's called and when it has the value 4 - meaning the load is complete, it displays the responseText
to the user with an alert.
xmlhttp.open("GET", "test.txt",true); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { alert(xmlhttp.responseText) } } xmlhttp.send(null)
With a HEAD request, a server will only return the headers of a resource, rather than the resource itself, this means you can find out the Content-Type or Last-Modified of a document, without downloading it itself.
A typical HEAD request might return something like this:
HTTP/1.1 200 OK Server: Microsoft-IIS/4.0 Cache-Control: max-age=172800 Expires: Sat, 06 Apr 2002 11:34:01 GMT Date: Thu, 04 Apr 2002 11:34:01 GMT Content-Type: text/html Accept-Ranges: bytes Last-Modified: Thu, 14 Mar 2002 12:06:30 GMT ETag: "0a7ccac50cbc11:1aad" Content-Length: 52282
To make a HEAD request, you simply replace the first parameter with HEAD, and then extract the headers, either using getAllResponseHeaders
or getResponseHeader("Name")
to get an individual one.
xmlhttp.open("HEAD", "/faq/index.html",true); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { alert(xmlhttp.getAllResponseHeaders()) } } xmlhttp.send(null)
One use of HEAD requests, is to find out when a url was modified, extending the previous example, you get something like this:
xmlhttp.open("HEAD", "/faq/index.html",true); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { alert("File was last modified on - "+ xmlhttp.getResponseHeader("Last-Modified")) } } xmlhttp.send(null)
To format the date differently, or use something other than alert, the javascript FAQ will tell you more.
Another simple use is finding if a url exists, in HTTP there are
various status codes returned by both HEAD and GET requests, 200 means
success, 404 means failure, and the others mean other things. See HTTP
status codes for a full explanation. using the status
property of the xmlhttp object provides you this status
xmlhttp.open("HEAD", "/faq/index.html",true); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { if (xmlhttp.status==200) alert("URL Exists!") else if (xmlhttp.status==404) alert("URL doesn't exist!") else alert("Status is "+xmlhttp.status) } } xmlhttp.send(null)
Forms are the way to "call" serverside scripts in HTML, they force the page reload, and this is often not very user friendly. Using the HTTP Request, you can call the script without refreshing the page, and still have the form "fallback" to working when the XML HTTP Request Object is not available.
<% a=+(Request.QueryString('a')+'') b=+(Request.QueryString('b')+'') if (isNaN(a) || isNaN(b)) {a='';b='';total='' } else { total=a+b } acc=Request.ServerVariables('HTTP_ACCEPT')+'' if (acc.indexOf('message/x-jl-formresult')!=-1) { Response.Write(total) } else { %> <script src="xmlhttp.js" type="text/javascript"></script> <script> function calc() { frm=document.forms[0] url="add.1?a="+frm.elements['a'].value+"&b="+frm.elements['b'].value xmlhttp.open("GET",url,true); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { document.forms[0].elements['total'].value=xmlhttp.responseText } } xmlhttp.setRequestHeader('Accept','message/x-jl-formresult') xmlhttp.send() return false } </script> <form action="add.1" method="get" onsubmit="return calc()"> <input type=text name=a value="<%=a%>"> + <input type=text name=b value="<%=b%>"> = <input type=text name=total value="<%=total%>"> <input type=submit value="Calculate"> </form> <% } %>
The example above uses JScript in ASP as the server side language, the HTTP ACCEPT header is used to tell the server which response to send back - either the full page or just the result. The HTTP ACCEPT header is used to tell servers what mime-types the client will accept, normally it says things like text/html etc. Here though we tell it we only accept "message/x-jl-formresult", so the server knows it is our client (or another client, who knows about "message/x-jl-formresult") making the request.
Other methods of identifying what to return may be appropriate depending on the type of data you send to the server, or you could simply use different urls for the form submission and xmlhttp request, whatever you do, remember to have sensible fallback to the non-xml http request browsers where possible.
Google provides a SOAP interface to it's database. You need to register for a key that lets you make 1000 a day, to make a request. You then need to parse the returned XML.
search="Word" xmlhttp.open("POST", "http://api.google.com/search/beta2",true); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { alert(xmlhttp.responseText) } } xmlhttp.setRequestHeader("Man", "POST http://api.google.com/search/beta2 HTTP/1.1") xmlhttp.setRequestHeader("MessageType", "CALL") xmlhttp.setRequestHeader("Content-Type", "text/xml") xmlhttp.send("<?xml version='1.0' encoding='UTF-8'?>"+"\n\n"+"<SOAP-ENV:Envelope"+ ' xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"'+ ' xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"'+ ' xmlns:xsd="http://www.w3.org/1999/XMLSchema">'+ '<SOAP-ENV:Body><ns1:doGoogleSearch'+ ' xmlns:ns1="urn:GoogleSearch"'+ ' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'+ '<key xsi:type="xsd:string">GOOGLEKEY</key> <q'+ ' xsi:type="xsd:string">'+search+'</q> <start'+ ' xsi:type="xsd:int">0</start> <maxResults'+ ' xsi:type="xsd:int">10</maxResults> <filter'+ ' xsi:type="xsd:boolean">true</filter> <restrict'+ ' xsi:type="xsd:string"></restrict> <safeSearch'+ ' xsi:type="xsd:boolean">false</safeSearch> <lr'+ ' xsi:type="xsd:string"></lr> <ie'+ ' xsi:type="xsd:string">latin1</ie> <oe'+ ' xsi:type="xsd:string">latin1</oe>'+ '</ns1:doGoogleSearch>'+ '</SOAP-ENV:Body></SOAP-ENV:Envelope>')
Google is using a SOAP interface, many people think SOAP has some serious issues worth considering. REST is probably a better model as it works with the current web framework, proxies, caches etc. So whilst we can use the XML HTTP Request object to talk soap, it's probably best not to unless you have no control over what's happening on the server end. (Thanks to Dan Schmierer for pointing out an error in my script.)
By default the object can only call back to the same server, in a reduced security environment (accessed from file:// say) IE can access any domain, Mozilla can also do that if you request and are granted the appropriate permissions see "a google thread I can't get to offline!"