Using the XML HTTP Request object

Using the XML HTTP Request object

This article was originally written in April 2002, I've decided to fix and update it as the objects finally seem to be getting some popularity. The 2002 version is still available. This version December 2004, there's also a September 2004 version.

Internet Explorer on Windows, Konqueror, Safari on Mac OS-X and Mozilla on all platforms provide a method for client side javascript to make HTTP requests, Opera 7.6preview 1 also now features the object. 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. These methods are increasingly used to provide richer Web Applications like G-Mail that use lower bandwidth and offer snappier user response.

Safari Warning

Steve Jenson suggests that the Safari implementation is completely hobbled in that it can only do GET and POST, this is clearly inadequate, hopefully this will be fixed in future versions.

Opera Warning

Opera 7.6 preview 1, is currently rather broken, it has a basic implementation of the object - you'll see that it's full of bugs such as double results and missing methods to set or get the headers, rendering it not as useful, again I'm sure this will come up to standard soon. Opera 8 beta 1 hasn't fixed all these bugs, but it's getting better. Because of Repeated ReadyState 4 events you should never assume each request results in only one Complete response, so if you code anything that adds in the complete event you should use a flag to ensure that each request hasn't already been acted on.

Why XML HTTP Request object?

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, although dealing with binary streams can be problematical in javascript.

Creating the object

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 and Safari (and likely in future UA's that support it) 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 and recovery with degrading to more normal HTTP transaction methods when the object isn't available. This degradation is important, even in IE the objects can often be blocked by slightly raised security settings (popular due to the commonly exploited holes of course). Where possible degrade, some approaches are talked about below, if you really can't, I'd recommend providing an alternative page aswell. GMail for example has said they'll be providing a less demanding version in the future, hopefully with no javascript at all, full degradation.

var xmlhttp=false;
   
   
/*@cc_on @*/
   
   
/*@if (@_jscript_version >= 5)
   
   
// JScript gives us Conditional compilation, we can cope with old IE versions.
   
   
// and security blocked creation of the objects.
   
   
 try {
   
   
  xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
   
   
 } catch (e) {
   
   
  try {
   
   
   xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
   
   
  } catch (E) {
   
   
   xmlhttp = false;
   
   
  }
   
   
 }
   
   
@end @*/
   
   
if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
   
   
  xmlhttp = new XMLHttpRequest();
   
   
}
   
   

How do I make a request?

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)
   
   

Making a HEAD request

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)
   
   

Using HEAD requests, to find the Last-Modified of another file.

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.

Does a url exist?

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)
   
   

Calling a server-side Script without refreshing the page

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" οnsubmit="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.

Never use sync in a webpage

All the examples here use the async mode (the third parameter of open set to true), this is important. Whilst the object can make sync requests, it's very bad on the user - the UI locks whilst the request is being made, if the request is long enough, a windows user may even see the "Not Responding" message and decide to kill the browser. Since you can do everything you wish with the ASYNC mode, always stay with that, your users will thank you, and you're much less likely to run the risk of lock-ups when more than 2 dependant requests are made at the same time.

Using XMLHTTP with GOOGLE's SOAP API

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 IE can access any domain, Mozilla can also do that if you request and are granted the appropriate permissions - UniversalXPConnect UniversalBrowserAccess, see the mozilla documentation.

Nearby...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值