ASP 101 - Active Server Pages 101 - Web05
The Place ASP Developers Go!

Please visit our partners


Windows Technology Windows Technology
15 Seconds
4GuysFromRolla.com
ASP 101
ASP Wire
VB Forums
VB Wire
WinDrivers.com
internet.commerce internet.commerce
Partners & Affiliates














ASP 101 is an
internet.com site
ASP 101 is an internet.com site
IT
Developer
Internet News
Small Business
Personal Technology

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

ASP 101 News Flash ASP 101 News Flash


 Top ASP 101 Stories Top ASP 101 Stories
The Top 10 ASP Links @ Microsoft.com
What is Adovbs.inc and Why Do I Need It?
An Overview of ASP.NET

QUICK TIP:
Using " in your Strings
Show All Tips >>
ASP 101 RSS Feed ASP 101 Updates


Creating Custom Error Pages

We saw earlier in the chapter just how effective a custom error page can be on your site. It can help you to retain visitors that found you site through an old or partially broken link, or those one-fingered typists who still insist on using the other nine thumbs to enter URLs into their browser's address box. As long as the link gets that visitor to your site (i.e. it includes your domain) it doesn't matter if the rest, the path and filename, is wrong. The visitor will get the custom error page.

The Custom '404 Not Found' Page

The error messages that your visitors see in their browser are just ordinary HTML pages. With Internet Information Server 4, when they request a page that doesn't exist, the page 404.htm (stored by default in the Winnt\help\common\ folder of your server) is sent back instead. This means that we can edit this file to personalize it, and-more important-add links to it that take the lost visitor to our Home page or site map.

We can also use a different page, stored in a different directory on our server, or specify the URL of a page stored elsewhere. This means that we can effectively redirect users to another site if that is appropriate. In this case, the target page can be an ASP script instead of the default of an HTML file. And, best of all, by combining these two techniques it's possible to persuade IIS4 to use an ASP page stored on our own server. This allows us to execute a script in response to a navigation error or broken link-exactly the plan we had in mind.

Setting Up the naverror.asp Page in IIS4

The first point to note is that IIS treats custom error pages that contain ASP code differently when it loads them in response to an error. If an ASP page is just specified as a file (in the IIS error configuration settings), any script code in it won't be executed. To make our custom error page work, we have to specify it as being a URL. Also note that this technique isn't limited to just 404 Not Found errors-there are a whole host of different errors defined and detected within IIS, and there is a default HTML page for each one. You can apply the following technique to any of these pages.

In IIS4, you can specify individual directories for which the custom error page will be used, so you can have different combinations of custom pages for each error in each directory or virtual directory. In IIS3, you can only specify one set of pages for the entire WWW sever.

Internet Service Manager Configuration

The first step is to build the custom error page we want to use. We'll show you how the one we use works after we see how to set up the custom error configuration within IIS, because there are issues involved that we'll have to resolve later in our code. We're going to apply our custom page to the entire Web site, so in the Internet Service Manager we right-click the Default Web Site entry and open the Properties dialog. In this dialog, open the Custom Errors page, scroll down to the entry for 404 Not Found, and click the Edit Properties button:

This displays the Error Mapping Properties dialog, where we change the Message Type from File to URL, and enter the URL of the ASP page to be executed when the error occurs. Here it's named naverror.asp, and is in the root folder of our site.


Because we are editing the properties of the default site, clicking OK brings up the Inheritance Overrides dialog. We don't want our custom error page used with the two child nodes (virtual applications) shown, so we click OK here without selecting them.

You'll probably see a different list of child nodes, depending on where you are specifying your custom page, and what virtual applications you have set up on your server.


How IIS Loads the Custom Page

With configuration complete in Internet Service Manager, our custom page will now be used instead of the standard 404 Not Found error page, and sent to the browser with every instance of this error. However, one point to note is that the way IIS loads the page depends on what type of file caused the error in the first place.

The next screenshot shows two error instances, one for an HTML file that doesn't exist and one for an ASP page. Notice that the URL for the missing ASP page is the name of our custom error page with a query string containing the error number and the full URL of the page that was requested. In the case of the HTML page that doesn't exist, the URL is just that of the missing file. You'll see why this is important when we look at the code in the page.

The Code for the naverror.asp Page

Now that we know what to expect from IIS when our custom error page is loaded, we can look at the code. The first part creates a ' 404 Not Found' status value to return to the browser, indicating that the page it requested does not exist. Then it defines the heading for the page:

<%@LANGUAGE="VBScript"%>
<% Response.Status = "404 Not Found" %>
<html>
<meta NAME="robots" CONTENT="noindex">
<head><title>Wrox Web-Developer Navigation Error</title></head>
<body BGCOLOR="#FFFFFF">
<img SRC="/images/WDLogoLg.gif" ALT="Wrox Web-Developer"><BR>
<font FACE="Arial" SIZE="4" COLOR="darkgray">
&nbsp; <B>Navigation Error</B></font>
<hr><P>
<font FACE="Arial" SIZE="3">The page you requested cannot be found.</font><P>
...

Of course, you'll want to be sure to put a robots type <META> tag with the value noindex in this page, as shown in the code above, to prevent search engines indexing it!

Collecting the Values We'll Need

Now we can collect the two values we'll need-the URL of the page that the user requested, and which wasn't found, and the URL of the page that contained the link they clicked. If they simply typed the URL into their browser's address box, this will be empty. We're going to store the details using two varchar-type fields in our SQL Server table, which are limited to 255 characters.

The final part of this section of code creates the information strings that we'll put into the page. The ones we actually end up using will depend on the values we obtained for the target and referrer. We also need to limit the referring URL in strReferer to 220 characters so that, even when added to the rest of the error message, it is no more than 255 characters long:

...
<%
On Error Resume Next 'important in an error page to prevent another error
strTarget = Request.ServerVariables("QUERY_STRING")
strReferer = Request.ServerVariables("HTTP_REFERER")
If Len(strReferer) > 220 Then strReferer = Left(strReferer, 220)
strInform = "Please inform the WebMaster of the site that contains the link."
strTyping = "Please check the URL and try again or:"
strRecord = "Error has been recorded and will be fixed as soon as possible."
strSQLInfo = "The page " & strReferer & " contains a broken link."
...
You'll recall from our earlier discussion on how IIS loads the custom error page that, if the request was for a missing ASP page, the target URL returned by IIS contains the URL of our error page followed by a query string containing the error number, a semi-colon, and the URL of the target page. The next step is to extract this by stripping it off the end of the original target string in strTarget. If there's no semi-colon, we know that it's an HTML page that caused the error, and so strTarget will just contain the target URL. Then we can trim it to a maximum of 255 characters, so as to fit into our table's varchar-type field. We also write it into the page:

...
intSemiColon = InStr(strTarget, ";") 'get the original target
If (intSemiColon > 0) And (intSemiColon < Len(strTarget)) Then
strTarget = Mid(strTarget, intSemiColon + 1)
If Len(strTarget) > 255 Then strTarget = Left(strTarget, 255)
End If
Response.Write "<B>&gt; &nbsp;" & strTarget & "</B><P>"
...
Having got our final target string, we can now examine the referrer information we saved in the strReferer string. If this is empty, it indicates that the user typed the URL themselves, so there's not much point in storing the values. However, if it's not empty, we know the user came from another page. In this case, we'll store the values for the target and referrer in our database, because they indicate a broken link:

...
If Len(strReferer) > 0 Then 'they came from a link on another page
Response.Write "A link on the refering page:<B> " & strReferer _
& "</B> contains an error.<BR>"
...
'write the values into the NavErrors table
...
Else
Response.Write strTyping 'they just typed it wrong into their browser
End If
%>
...
Storing the Values in the Database

To get the values into the database, we just create our Connection object, open it, and fire a suitable SQL INSERT statement at it. The connection string is defined in the variable strConnect by using an include file, as we've done in previous chapters. However, you can specify a suitable DSN instead if required:

If Len(strReferer) > 0 Then 'they came from a link on another page
Response.Write "A link on the refering page:<B> " & strReferer _
& "</B> contains an error.<BR>"
Set oConn = Server.CreateObject("ADODB.Connection") 'to store the details
oConn.Open strConnect 'defined elsewhere in the page
strSQL = "INSERT INTO NavErrors (NavError, TargetURL) " _
& "VALUES ('" & strSQLInfo & "', '" & strTarget & "')"
oConn.Execute strSQL
If Err.Number = 0 And InStr(strReferer, ".wrox.co") > 0 Then
Response.Write strRecord 'came from a page on our site
Else
Response.Write strInform 'came from a page on another site
End If
Else
Response.Write strTyping 'they just typed it wrong into their browser
End If
Notice that, after we've stored the values in the table, we examine the referrer string to see if the link that caused the error is on our site or another site. Even though we've recorded both, we only tell the viewer it will be fixed if it's one of ours-that's the only time we can be sure it will. For other errors we ask them to let the referring site know about the error.

Of course, when we come to examine the table contents, we'll see the broken links on other sites. We can drop them an email to let them know, or put a default redirection page in place to catch any more referrals we get to the missing page.

Finally, we can finish up our custom error page with a couple of links to our Home page and site map:

...
<P><A HREF="/default.asp" TARGET="_top"><B>Click here to go to our Home page</B></A>.
<P><A HREF="/default.asp?bookcode=sitemap" TARGET="_top"><B>Click here for a map of our site</B></A>.
<P>or click the <B>Back</B> button in your browser to return to the previous page.
</body>
</html>
A Table to Store the Error Details

The code in the naverrors.asp page assumes that we have a suitable table (named NavErrors) already available to store the error details. If you implement the visitor logging and information system that we describe in the next chapter, and set up the database for it using the scripts that we supply, this table will be created for you in the IISLogs database.

If not, you can use the script naverrors.sql that is included with the samples for this chapter to create the table in another database instead. This is the table, as seen in SQL Server:

The table includes a field that can be used to store the IP address of the server-easily obtained from the Request.ServerVariables collection. This might be useful if you host several sites, which is why it is included. However, as you'll be able to see the referring URL in the values stored in the table, you may prefer to disregard this field as we've done.

Managing the NavErrors Table

Having stored all this useful data about the broken links on our and other people's sites, we'll need to be able to use it. Viewing and deleting the stored records is easy with ASP, and we'll very quickly show you how it can be done.

Viewing the Stored Broken Links Details

This page, viewbrokenlinks.asp, is included with the samples for the book. It simply opens the NavErrors table, using a connection string defined in an include file (as you've seen done many times earlier), and dumps the contents of the fields into an HTML table in the page. We haven't repeated the page headings again, but simply listed the code that does the work:

<%@ LANGUAGE=VBSCRIPT %>
<!-- #include virtual="/connect/iislog.inc" -->
<html>
...
<% '--get error information---
On Error Resume Next
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.Open strConnect 'from include file at top of page
strSQL = "SELECT ErrDateTime, NavError, TargetURL FROM NavErrors " _
& "ORDER BY ErrDateTime DESC"
Set oRs = oConn.Execute(strSQL)
If (oRs.EOF) Or (Err.Number > 0) Then
Response.Write "<FONT FACE=" & QUOT & "Arial" & QUOT & " SIZE=3>" _
& "<B>Sorry, database cannot be accessed.</B></FONT></BODY></HTML>"
Response.End
End If
%>
<table>
<tr>
<th nowrap>Date &nbsp; Time &nbsp;</th>
<th nowrap>Error Details</th>
</tr>
<% Do While Not oRs.EOF %>
<tr>
<td nowrap valign="top"><% = oRs("ErrDateTime") %> &nbsp;</td>
<td nowrap>
<% = oRs("NavError") %><BR><B>Target:</B> <% = oRs("TargetURL") %>
</td>
</tr>
<% oRs.MoveNext
Loop
Set oRs = Nothing
Set oConn = Nothing %>
</table>
...
As all the best chef's say, here's one we made earlier. You can see that we have a broken link on Yahoo, and a missing file on our own site:

Deleting the Stored Broken Links Details

Deleting the error details from the table, once we've fixed the links or reported the error to another Webmaster, is even easier. We just need to apply a SQL DELETE statement to the table to remove all the contents. The statement DELETE NavErrors does this, it doesn't drop (delete) the table itself. If you're feeling nervous about this, use DELETE FROM NavErrors instead-it does the same thing:

<%@ LANGUAGE=VBSCRIPT %>
<!-- #include virtual="/connect/iislog.inc" -->
<html>
...
<% If Request.QueryString("Sure") = "Yes" Then 'delete the table contents
On Error Resume Next
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.Open strConnect 'from include file at top of page
strSQL = "DELETE NavErrors"
Set oRs = oConn.Execute(strSQL)
If Err.Number > 0 Then
Response.Write "<FONT FACE=" & QUOT & "Arial" & QUOT & " SIZE=3>" _
& "<B>Sorry, the database cannot be accessed.</B></FONT></BODY></HTML>"
Response.End
End If
Set oRs = Nothing
Set oConn = Nothing %>
<P><B>All entries deleted...</B><P><A HREF="mainmenu.asp">Main Menu</A>
<% Else 'prompt for confirmation before deleting records %>
Are you sure you want to delete all the entries ? &nbsp;
<A HREF="<% = Request.ServerVariables("SCRIPT_NAME") %>?Sure=Yes">Delete</A>
&nbsp; <A HREF="mainmenu.asp">Cancel</A>
<% End If %>
</body>
</html>
Confirming the Delete Action

One trick you can see used in the code above is how we get the user to confirm the delete action first, by looking for a value Sure=Yes in the query string. When the page is first loaded this value won't be there, so we create the 'Are you sure' page that contains the Delete and Cancel links:


The Delete link, which reloads this page, contains the value Sure=Yes in the query string. So, this time, the code that deletes the records will be executed



BackContentsNext
�1998 Wrox Press Limited, US and UK.