Background HTTP fetching and cacheing in ASP/VBScript

We've recently had to integrate code with a large ASP application, which provided me with certain opinion-forming revelations about how the other half live. Part of this integration required us to write some ASP, an unexpected and un-wished-for surprise in itself. We had to generate livery in our own application---to make webpages from both sites consistent---and expose it to ASP via a HTTP call over the wire. The ASP application could then cache it, to avoid the extra per-page overhead of a HTTP call plus dynamic generation.

I provide below some reasonably solid HTTP fetching and cacheing in ASP/VBScript. I hesitate to add "because almost everything I found on the web was rubbish" because that would show hubris in the face of me having just had to sanitize the code, quite likely introducing typos along the way. These code samples also come with no warranty and no likelihood of me answering awkward questions about them. To invoke the fetcher/cacher, put the following in your currently executed VBScript file:

<% Dim strUrl, strUrlKey, objWinHttp
strUrlKey = "top_menus" %>
<!-- #include file="fetch.inc" -->
. . .
<% strUrlKey = "side_menus" %>
<!-- #include file="fetch.inc" -->
. . .
<% strUrlKey = "footer" %>
<!-- #include file="fetch.inc" -->

Some notes on this below, but here is the actual fetcher/cacher to put in fetch.inc and bring it in with the above:

<%
' @description remote calls to get livery
'
' @param strUrl might need to be Dim-defined in wrapping file
' @param strUrlKey must be Dim-defined and set to a particular
'   livery identifier in wrapping file - also appends it to the URL
'   query string that it gets
' @returns HTML on standard output

strUrl = "http://example.com/?livery=" & strUrlKey

' Cache timeout is 60 minutes
' Application(foo) fails gracefully if key foo does not exist
If DateDiff("n", Application(strUrl & ".LastModified"), Now()) >= 60 Then
  ' If cache expired, get the page
  Set objWinHttp = CreateObject("Msxml2.ServerXMLHTTP")
  ' Turn error handling on
  On Error Resume Next

  ' Timeouts will now be handled
  objWinHttp.open "GET", strUrl, False
  objWinHttp.send

  ' If no error, trust content
  If Err.number = 0 Then
    ' Lock the application scope and insert page and cache date
    Application.Lock()
    Application(strUrlKey) = objWinHttp.responseText
    Application(strUrlKey & ".LastModified") = Now()
    Application.UnLock()
  End If

  ' Turn error handling off
  On Error Goto 0

End If

' Regardless, read from the application
Response.Write(Application(strUrlKey))

' Tear down object
Set objWinHttp = Nothing
%>

The Dim statements before the <!--include--> make it all a real pain in the arse. Some server configurations will arbitrarily interpret and run ASP files without Dims; some won't. And you can only ever Dim a variable once in a particular variable scope, or everything dies horribly; you have to keep track of whether or not a variable has already been declared, pretty much by eye.

Depending on your server, you might also not have access to the particular DLL that provides Msxml2.ServerXMLHTTP. If that's the case, then there are other possible ways of making the HTTP call out there on the web: it's just that the Graceful Exits bouncer isn't letting them through the door.

Now, if you'll excuse me, I need a shower.

Comments

Erm, you declare "strKey" but don't use it, and assign to strUrlEnd, but appear to be using strUrlKey, have you been searching and replacing without recompiling?

Well, mostly I'm confusing sanitized code with an unmodified snippet to invoke it, as I added the invocation snippet to this post at the last minute. Should all be consistent now.

(I certainly haven't been able to test the sanitized version, if that's what you mean: it goes entirely against the grain, certainly; but it's impossible for various reasons that I'll tell you about later.)