In questi giorni mi sono trovato a dover dirimere un sottile conflitto sorto tra l'architettura ASP.Net e
le regole ferree cui i guru dei motori di ricerca consigliano i attenersi... espongo brevemente il problema:
- Scenario: sito web ben posizionato - in termini di motori di ricerca - costretto a migrare su nuovo dominio (il vecchio dev'essere svuotato di contenuti).
- Obiettivo: difendere ad ogni costo i page rankings sanguinosamente guadagnati! :)
- Note: tutte le pagine cui faccio riferimento sono .aspx (posso fare affidamento sull'ISAPI .Net).
Abbiamo avuto la dritta - dai sopracitati guru - che in casi come quello descritto, non potendo ri-presentare a - diciamo - Google
il contenuto della pagina solita, è preferibile rispondergli con un bell'errore 404 e qualche link accessorio nel corpo della pagina d'errore che possa indirizzarlo
verso i nuovi link...
Ecco qui l'idiosincrasia tra ASP.Net ed i motori di ricerca! Se cerchiamo di gestire gli errori 404 alla maniera usuale
(vale a dire utilizzando la sezione customErrors del web.config) otteniamo un risultato indsiderato:
supponiamo che la nostra pagina di errore 404 customizzata forzi come response uno statuscode 404...
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
void Page_Load(object o, EventArgs e)
{
Response.StatusCode = 404;
lbl.Text = Response.Status;
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>404 - Not Found</title>
</head>
<body>
<asp:Image runat="server" ID="img" ImageUrl="~/Images/Icons/ico_warning.gif" AlternateText="404" ImageAlign="Middle" />
<asp:Label runat="server" ID="lbl" Font-Bold="true" />
</body>
</html>
Ciò che otterremo sarà innanzitutto uno status 302 (che significa "redirect" o, in termini di motori di ricerca "cattivo") e quindi lo status 404!
(potete sperimentare questo comportamento utilizzando Fiddler)
* Tutto ciò è da evitare se si vogliono compiacere i motori di ricerca! *
Ecco la mia soluzione...
L'idea è quella di intercettare l'HttpException 404 via HttpModule e restituire il contenuto della
pagina scritta sopra.
Ecco la mia implementazione dell'interfaccia IHttpModule:
using System;
using System.Web;
namespace PacemWebSite.BLL.Web
{
class PacemHttpModule : System.Web.IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.Error += new EventHandler(context_Error);
}
void context_Error(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
Exception lastError = app.Server.GetLastError();
HttpException he = lastError as HttpException;
if (he != null)
{
int httpErrorCode = he.GetHttpCode();
if (httpErrorCode == 404)
{
app.Server.ClearError();
string fofPage = "~/Pages/404.aspx";
app.Context.Handler = System.Web.UI.PageParser.GetCompiledPageInstance(fofPage, app.Server.MapPath(fofPage), app.Context);
}
}
}
}
}
Viene da sé che è necessario aggiornare la sezione httpModules nel web.config come al solito:
<httpModules>
<add name="FourOhFourModule"
type="PacemWebSite.BLL.Web.PacemHttpModule, PacemWebSite"/>
</httpModules>
In questo modo il responso risulterà essere un diretto e "rassicurante" 404!
Take care. Bye.
Feedbacks
-
Re: 404 vs 302 ASP.Net Custom Errors
Scott (giovedì 22 marzo 2007 5.48)
“This is good. I moved it to the Application_Error event handler in the global.asax codebehind file. Means the code is repeated throughout different projects but means I don't have to register a module each time either or modify the module to allow configuration changes from the web.config file.”
-
Re: 404 vs 302 ASP.Net Custom Errors
CMerighi (giovedì 22 marzo 2007 13.31)
“Sure. It's about personal preferences... I love configurable modular environments: so that I just move my libraries and set (or not) this or that feature with relevant settings' values.
Cheers!”
-
Re: 404 vs 302 ASP.Net Custom Errors
Luke (mercoledì 8 agosto 2007 11.25)
“i couldn't get this to work, unfortunately. i managed to fix it by adding:
handler.ProcessRequest(app.Context);
it seems like in your code above you are relying on ASP.NET to call this for you. for some reason it doesn't for me...
”
-
Re: 404 vs 302 ASP.Net Custom Errors
charles k (mercoledì 15 agosto 2007 17.59)
“I'm new to ASP.NET. I'd like to implement your solution.
What would I name the class file?
Where would I save the class file? (App_Code > BLL).
When adding the custom HttpModule reference in web.config what is the significance of the content in the type="a,b" attribute.”
-
Re: 404 vs 302 ASP.Net Custom Errors
Walter (lunedì 14 luglio 2008 18.48)
“Ciao, ho trovato molto interessante il tuo articolo ma ho provato a riprodurlo e non funziona (nelle mie pagine). Sono un neofita di ASP.NET e fino alla riga string fofPage = "~/Pages/404.aspx"; tutto ok dopo cominciano i guai. Potresti darmi qualche dritta ???
Grazie in anticipo,
Walter.”
-
Re: 404 vs 302 ASP.Net Custom Errors
Mckensy (martedì 23 settembre 2008 3.41)
“Good point but what will happens on a HIGTH traffic enviroment. Processing all HTTTPrequest could cause a massive deadlock :(”
-
Re: 404 vs 302 ASP.Net Custom Errors
CMerighi (martedì 23 settembre 2008 6.17)
“@Mckensy:
well, I consider it a lightweight procedure which - besides - only runs when an exception of type HttpException and with code 404 occurs. If I couldn't customize my site's "not-found-page" and will notice slow responses, I don't think I'll put the blame on this piece of code.
But, if you know about issues I should keep in mind, better performing code or alternative solutions please let me know!... Thank you.”
-
Re: 404 vs 302 ASP.Net Custom Errors
Netguy (mercoledì 6 maggio 2009 4.50)
“This is great and I'm using it in my website, thanks for sharing. I had to add a call to ProcessRequest like Luke suggested and it worked.
However I encountered another problem: it is a requirement that i can access session state in the 404 page, but when the 404 is caused by my Url Rewriter (this is the url rewriting from urlrewriter.net and fires at the BeginRequest event which is before session is created).
Session is null at this stage but also remains null, and I cannot find a way to make the system generate it.
I tried deriving this HttpModule from IRequiresSessionState, but still nothing.
Any suggestions? any help would be much appreciated..!”
-
Re: 404 vs 302 ASP.Net Custom Errors
Matt (martedì 19 maggio 2009 20.37)
“I just moved
Response.StatusCode = 404;
to Page_Init, and I don't get the 302 before the 404.”
-
Re: 404 vs 302 ASP.Net Custom Errors
Kapil (martedì 22 settembre 2009 6.07)
“I tried this, it worked fine on my development machine but when i deployed it on production, it is not doing anything.
Could you please let me know what to do to get it worked on production.
I am using IIS 6.0 and windows server”