Recent posts to our Discussion
Forums on Eggheadcafe.com lead me to see that there may be many people
who are having difficulty understanding how to use XMLHTTP and SERVERXMLHTTP
correctly. In particular, people tend to confuse the methods needed to
send form data, which is TEXT, vs. sending a complete XML DOMDocument
object, which is treated differently.
Since I've already gone through most of
the pain involved in learning this tool, I'm taking this opportunity to
share some of the things I've learned. First, let me say that XMLHTTP
gives the developer a totally unique paradigm in the development of web-
based applications, particularly in that we now have the ability to make
the client browser far more intelligent and intuitive, to store often
- used data there, and to avoid much of the constant form posts and round
trips and database calls that previously placed a high load on the webserver.
You can now use a form post NOT to go
to the webserver, process your page all over again, and return results
to the browser, but instead, you can store frequently used data in XML
data-islands in a topmost IFRAME for example, and have global Javascript
functions that take data that has changed on the client (in forms for
example) and use the onChange events to update your XML data island. When
the data is finally ready to be sent to the server, instead of posting
the form to the webserver, instead you can now call XMLHTTP to send your
XML data island without the unprofessional-looking and server-intensive reloading of the originating
page. On top of that, you can return results and refresh the contents
of areas of the client page through well -exposed DOM methods, also without
reloading the page. This makes for a much more intuitive, "Windows-like"
user experience and also helps our application scale better in a heavy
load scenario because there is less load on the webserver and the database.
One of the most important things you'll
probably need to do in order to get ServerXMLHTTP working properly is
to run
Proxycfg -d on the machine that's going to be using it. You can
find this tool here: http://msdn.microsoft.com/code/sample.asp?url=/msdn-files/027/001/468/msdncompositedoc.xml
What we are going to illustrate in this
short article is:
1. How to send form data (NOT XML)
using xmlhttp, receive it on the server side, process it, and send back
a result to the originating client. The originating client page will never
reload.
2. How to set a custom request header
in the originating client page, have this received and processed at the
server, and a result also sent back in the result stream.
First, let's design our client page,
"SendReqHeader.htm":
<TABLE
border='2' align='center'>
<TR><TD colspan="2" align="center">"Last-Cached" Custom
<BR>Header Control Demo</TD></TR>
<TR><TD width="150" align='center'>
<LABEL>Name</LABEL>
</TD><TD>
<input name='Customername' type="edit"/>
</TD></TR>
<TR><TD width="150" align='center'>
<LABEL>Telephone number</LABEL>
</TD><TD>
<input type="edit" name="telno"/>
</TD></TR>
</TABLE>
<TABLE align='center'>
<TR><TD width="150" align='center'>
<input type='button' value='send Information' align='center' onclick='sendinfo()'/>
</TD></TR>
</TABLE>
<script language="vbscript">
function sendinfo()
Dim myhttp
if(not(Customername.value = "")) then
datatosend="Name=" & Customername.value & "&TelNo="
&telno.value
Set myhttp=CreateObject("Msxml2.XMLHTTP")
myhttp.open "POST", "http://localhost/XMLREQHEADER/httpreqserver.asp",
false
myhttp.setRequestHeader "lastCached", now()
myhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
txtSent.innerText =datatosend
' To the Moon, Alice.....
myhttp.send datatosend
reqstatus.innerText = myhttp.status
txtResult.innerText= myhttp.responseText
set myhttp = Nothing
else
txtSent.innerText= "invalid data"
set myhttp = Nothing
end if
end function
</script>
Status:<div id=reqstatus></div><BR>
Sent:<div id=txtSent></div><BR>
Rec'd:<div id=txtResult></div>
What this page does is get two input values
from the user (Customername and TelNo) and create the same type of string
from them that a normal form post would contain, in the format :
"Name=John&TelNo=4075551239".
Then, it sets a custom header using the
setRequestHeader method consisting of the name "lastCached"
having a value of now(), which is the VBScript DateTime method. We then
must set the Content-Type request header to "application/x-www-form-urlencoded"
in order to tell the receiving page that this is a FORM POST, not a regular
HTTP GET or any other type of action. Once we do this, the receving ASP
page will be able to access the contents of the form collection in the
same way most ASP developers are familiar with: Request.Form("Name")
and Request.Form("TelNo"). And of course the data is
actually POSTED by the XMLHTTP control, NOT by any HTML FORM control.
In fact, as I am sure you've noticed, there isn't a FORM control to be
found anywhere on this page.
We've also set up a few DIV's to enable
us to display what was sent, the XMLHTTP status property, and the results
we get back from the XMLHTTP responseText property. Even though we are
going to be sending back well-formed XML from the server page, I've used
the responseText method in order to be able to display the results. In
a production environment, we'd probably be loading the result XML into
a DOMDocment object and doing further processing, such as updating an
XML data island or some area of the user interface controls.
Now let's look at what's happening on
the server in "HttpReqServer.asp":
<%@
language=javascript %>
<%
Response.Expires = -1000;
var result = Server.CreateObject("MSXML2.DOMDocument")
var OutputString="";
var customHeader = Request.ServerVariables("HTTP_lastCached");
OutputString+="<Name>" +Request.Form('Name') +"</Name>"
OutputString+="<TelNo>" +Request.Form('TelNo') +"</TelNo>"
// Get milliseconds between now and when "LastCached" header
was created
var timeDiff = new Date(customHeader);
timeDiff = new Date()-timeDiff;
var resTime="<TimeDiff>" +timeDiff + "</TimeDiff>";
OutputString+=resTime;
if(customHeader != "")
{
result.loadXML("<result>" + OutputString +" </result>");
var pi = result.createProcessingInstruction("xml", "version='1.0'");
result.insertBefore( pi, result.firstChild);
result.save(Response);
result.erase;
}
else
{
Response.Write("<P><B>" + OutputString+" </B></P>");
}
%>
Here, we are instantiating a DOMDocument
object to handle our result document. We grab the custom Header "lastCached"
using the Request.ServerVariables("HTTP_lastCached") ASP intrinsic
method (Custom headers have "HTTP_" prepended to them in the
servervariables collection).
We begin building a response XML document:
OutputString+="<Name>"
+Request.Form('Name') +"</Name>", and we set a
new Date object using the value of the customHeader we sent from the client.
We then create a second date object and do date arithmetic to get the
number of milliseconds difference between when the custom Header was created
and now. This type of procedure can be used to check the last time a page
was loaded (cached) by the client and is extremely useful in making decisions
about what and whether to send data back to the client. In this simple
example we are simply going to show the time difference and send it back
along with the data that was sent, so we load it all into our DOMDocument.
We then use the createProcessingInstruction
DOM method to add the standard XML PI to the beginning of our document,
and SAVE it directly into the Response object. You can do this because the Response object supports streams and that is what a Saved xml DOM object is. (you can also LOAD a request stream into an XML DOMDocument object) . And out it goes, right
back to the XMLHTTP on the client which has been patiently listening for
its return document, and we display our stuff with the innerHTML or innerText DHTML DOM element methods.
So there you have it. It's not your father's XML.
download the code that accompanies
this article
Peter Bromberg is an independent consultant specializing in distributed .NET solutionsa Senior Programmer / Analyst at
in Orlando and a co-developer of the NullSkull.com
developer website. He can be reached at info@eggheadcafe.com
|