Handling Live Web Content in WSH - Part 2

In part one of this article we began to explore the XMLHttpRequest object and how it could be used to interact with live web content. We focused primarily on reading the contents of a web page (a technique known as “screenscraping”) and parsing that data into our script. This time we are going to take a look at the rest of the methods provided by the XMLHttpObject and how we can use them to send data to a web server for remote form submission.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 4
December 19, 2006
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

You may want to review part one of this article before going any further if you need to refresh your memory. The XMLHttpRequest object is a versatile tool because it’s installed by Internet Explorer (which means that it’s native to every machine on which you run your script). Its simple construct also makes coding this into your scripts as painless as possible.

We’re going to use the XMLHttpRequest object to submit POST data to a form. In order to do this we’ll need two things. The first is the full URL where we want to send our request. You can find this by looking at the source code for the form.  The URL will be in the action attribute of the <form> html tag. Remember that this may be a relative reference so you may have to include the rest of the URL from your browser’s address bar. I have uploaded a sample form to use when testing this script. It is located at the following URL:

http://images.devshed.com/af/stories/hlwc2/testform.php

Next, we need to construct our POST data string.  This is just a string that contains simple data field-value pairs for the form fields that we want to submit.  Each data field is separated from the next by an ampersand (&) just as if we were appending it to a URL. The only difference is that we do not need to encode it, so any special characters are okay.

Our example uses two form fields: “name” and “address.” It also contains a hidden field named “action” whose value is set to “data” by default. Let’s assume we want to submit the following data in our form:

Name:    John Doe

Address: 123 My Street

With this information, we would construct the following POST data string which I’ve separated across two lines for aesthetic purposes:

strPostData = “action=data&name=John Doe” _

   & “&address=123 My Street”

actionURL = “http://images.devshed.com/af/stories/hlwc2/testform.php”

Making the Connection

Now that we have our data in order, it’s time to send it to the server.  We’ll begin by connecting to the XMLHttpRequest ActiveX object with a CreateObject() method call to its namespace.  In the last article we used “Microsoft.XMLHTTP” as our namespace.  This time we’ll use a newer version that should be installed on every machine with Internet Explorer 5 or higher.  If you experience errors, just use the older one.

Set objxmlHTTP = CreateObject(“Msxml2.XMLHTTP”)

Next we open our connection with the XMLHttpRequest object’s Open() method.  I’ll provide the syntax again for those who need a refresher.

object.Open(“method”, “URL”[, asyncFlag[, “username”[, “password”]]])

The first parameter is a text string containing the HTTP method that we wish to use, in our case, “POST.”  The method should be in all caps.  The second parameter is a string containing the form action URL.  The third and final attribute we’ll be using is an optional Boolean value that tells the XMLHttpObject whether or not the data should be sent asynchronously.

The final two parameters are the username and password, respectively, which we would use if our connection prompted for authentication.  It should be noted that the username and password values will only be sent if requested by the server.

So continuing on, we open our connection as follows:

objxmlHTTP.Open(“POST”, actionURL, True)

objxmlHTTP.setRequestHeader “Content-Type”, _

   “application/x-www-form-urlencoded”

objxmlHTTP.Send(strPostData)

We’ve used the XMLHttpRequest object’s setRequestHeader method to tell the server the MIME type of the data we are posting.  This can usually be omitted, but is required by some servers.  We then use the Send() method to send our POST data string by setting it as the parameter.  Syntax for the Send() method is shown below.

object.Send([“data”])

Handling the Response

The XMLHttpRequest object has built two built-in properties, ResponseText and ResponseXML, which capture the data returned by the server.  The methods return the data as text or as an XML object respectively.

result = objxmlHTTP.ResponseText

Wscript.Echo result

We’ll finish up by echoing back the HTML text that was returned (which happens to be the source for our form submittal page).  Our result should look something like this:

<html>

<head>

<title>XMLHttpRequest Test Form</title>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

</head>

 

<body>

<font color="#FF0000">This form was submitted remotely.</font><p>Name : John Doe<br>

Address : 123 My Street<br>

</body>

</html>

So our complete code example would look like this:

strPostData = “action=data&name=John Doe” _

   & “&address=123 My Street”

actionURL = “http://images.devshed.com/af/stories/hlwc2/testform.php”

 

Set objxmlHTTP = CreateObject(“Msxml2.XMLHTTP”)

 

objxmlHTTP.Open(“POST”, actionURL, True)

objxmlHTTP.setRequestHeader “Content-Type”, _

   “application/x-www-form-urlencoded”

objxmlHTTP.Send(strPostData)

 

result = objxmlHTTP.ResponseText

Wscript.Echo result

 

Set objxmlHTTP = Nothing

Handling Errors and Exceptions

That was simple enough, but now what?  There has to be more to it.  For instance, what if there is a server error while we are trying to connect?  How would we know, and better yet, how could we handle that in our script so that our script wouldn’t fail?

In this section, I will be dealing with several more parts of the XMLHttpRequest object.

Properties:

object.ReadyState

object.Status

object.StatusText

 

Methods:

abort()

getAllResponseHeaders()

getRespondseHeader()

 

Events:

onReadyStateChange (not used)

In order to catch errors and respond to them, we first need ways of monitoring what’s going on.  There are basically two ways of doing this: by monitoring the XMLHttpRequest object’s connection state and by monitoring the server's HTTP response codes.  The ReadyState and Status properties do that for us respectively.  The ReadyState property returns one of five possible integer values as listed below based on the connection state of the XMLHttpRequest object.

Value

State

Description

0

Uninitialized

Waiting for the Open method.

1

Loading

Waiting for the Send method.

2

Loaded

Send method called.  Status and headers available.

3

Interactive

Some data received.  You may use ResponseBody and ResponseText to see currently available data.

4

Complete

All data has been received.

The Status and StatusText properties are used to monitor the server responses.  Status will return a numerical HTTP code and Status Text will return its text equivalent.  So examples might be “404” and “Not Found”, respectively.

With these properties, we can easily monitor our conditions on both the client side and the server side.  Our first concern would be a connection error in the form of a timeout.  If we can’t make a connection in a reasonable amount of time we should stop the attempt before it throws an error in our script.

Implementing a Workaround

By design, the XMLHttpRequest object has an event called onReadyStateChange for this.  However, it isn’t fully supported and doesn’t work with VBScript, so we’ll create our own workaround in the form of a  timeout loop after we call the Send() method.

varCounter = 0

Do Until (objxmlHTTP.ReadyState = 4) Or (varCounter = 30)

   varCounter = varCounter + 1

   Wscript.Sleep(1000)

Loop

We start by creating a counter variable.  Then we create a loop that increments our counter.  The loop will break out any time our ReadyState indicates that the connection is complete or when approximately 30 seconds have passed.  We use the Sleep() method to ensure that each iteration takes approximately one second.

Now we’re ready to set up some conditional statements.  We need to first determine whether a timeout error has occurred.  If so, we should quit trying to make the connection.

If varCounter = 30 Then

   objxmlHTTP.Abort()

   result = "Your request has timed out. Please try again later."

We use the XMLHttpRequest object’s Abort() method to stop any transfer attempts and then set the result string variable to notify the user.

Elseif objxmlHTTP.Status <> 200 Then

   result = objxmlHTTP.Status & ": " & objxmlHTTP.StatusText

Now we perform a quick check to make sure that no server errors occurred.  We can do this by checking that the Status property equals 200 (or OK).

Finally, we can process our results.

Else

   result = objxmlHTTP.ResponseText

End If

Our Else statement sets our result equal to the text data returned by the XMLHttpRequest object.  We’ll finish by closing the connection (by emptying our object) and echoing the results like we did in the last example.

Here are two example outputs after a timeout error and a server error, respectively.

Your request has timed out.  Please try again later.

 

404: Not Found

I’ve included this workaround into the completely reusable function available in the source code for this article.  The code also includes an additional function for providing text-based error codes based on the ReadyState property.

Other Uses for XMLHttpRequest

Right about now you’re probably asking what else you can do with the XMLHttpRequest object.  Well, here are a couple of other uses for you to play around with.

object.getResponseHeader(“header”)

The XMLHttpRequest object is also able to request a website’s headers.  It provides two different methods for doing this.  The getAllResponseHeaders() method will return all of the headers supplied by the server.  The getResponseHeader() method can be used to request a specified header only.  The following example demonstrates both.

Set objxmlHTTP = CreateObject("Msxml2.XMLHTTP")

objxmlHTTP.Open "HEAD", "http://www.aspfree.com", False

objxmlHTTP.Send()

 

Wscript.Echo “Return all headers:”

Wscript.Echo objxmlHTTP.getAllResponseHeaders()

Wscript.Echo “Return last modified date:”

Wscript.Echo objxmlHTTP.getResponseHeader("Last-Modified")

 

Set objxmlHTTP = Nothing

As you can see, we’ve used the getAllResponseHeaders() method to return all of the headers and the getResponseHeader method to return the Last-Modified headers.  An example output might look like this:

Return all headers:

Date: Fri, 01 Dec 2006 20:00:05 GMT

Server: Apache/1.3.34 (Unix)

Set-Cookie: sessioncookie=c88b42fa00eb0b52045e8b3ce1621c5; expires=Sat, 01-Dec-2007 20:00:05 GMT; path=/

Set-Cookie: usercookie=c88b42fa00eb0b52045e8b3ce1621c5; expires=Sat, 02-Dec-2006 08:00:05 GMT; path=/

Set-Cookie: jamcku=nilpo; expires=Sat, 01-Dec-2007 20:00:05 GMT; path=/

Set-Cookie: jamckp=8ad7de41a5d1bda96b57ff2ca0e0b697; expires=Sat, 01-Dec-2007 20:00:05 GMT; path=/

 

Set-Cookie: mosvisitor=1

Expires: Mon, 26 Jul 1997 05:00:00 GMT

Last-Modified: Fri, 01 Dec 2006 20:00:05 GMT

Cache-Control: no-store, no-cache, must-revalidate

Cache-Control: post-check=0, pre-check=0

 

Pragma: no-cache

Keep-Alive: timeout=10, max=150

Connection: Keep-Alive

Content-Type: text/html

 

Return last modified date:

Fri, 01 Dec 2006 20:00:05 GMT

Wipe the sweat off of your forehead and pour yourself a cold glass of tea.  The hard work is done.  You now have two more uses for the XMLHttpRequest object as well as some good methods for error-handling when using it.  That’s it for now.  I’ll catch you next time.  Until then, keep on coding!

blog comments powered by Disqus
WINDOWS SCRIPTING ARTICLES

- More Windows Scripting Workarounds from Nilpo
- Overloading Methods and More in VBScript
- Improving MFC for Windows Vista
- Regular Expressions in VBScript
- Working with Dates in WMI
- Completing Calendars with VBScript Date Func...
- Building Calendars with VBScript Date Functi...
- Working With Dates and Times in VBScript
- Designing WCF DataContract Classes Using the...
- Understanding Dates and Times in VBScript
- Working With Arrays in VBScript
- Compressed Folders in WSH
- Using .NET Interops in VBScript
- Nilpo`s Scripting Secrets, Vol I
- Database operations using Silverlight 2.0 WC...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 5 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials