ASP.NET Custom 404 Devuelve 200 OK en lugar de 404 No encontrado

80

Después de intentar configurar mi sitio para Google Webmaster Tools, descubrí que mi página personalizada ASP.NET 404 no devolvía el código de estado 404. Mostró la página personalizada correcta y le dijo al navegador que todo está bien. Esto se considera un 404 suave o un 404. falso. A Google no le gusta esto. Así que encontré muchos artículos sobre el tema, pero la solución que quería no parecía funcionar.

La solución que quiero trabajar es agregar las siguientes dos líneas al código detrás del método Page_Load de la página 404 personalizada.

Response.Status = "404 Not Found";
Response.StatusCode = 404;

Esto no funciona. La página todavía devuelve 200 OK. Sin embargo, descubrí que si codifico el siguiente código en el código de diseño, funcionará correctamente.

<asp:Content ID="ContentMain" ContentPlaceHolderID="ContentPlaceHolderMaster" runat="server">

<%
    Response.Status = "404 Not Found";
    Response.StatusCode = 404;
%>

 ... Much more code ...

</asp:content>

La página utiliza una página maestra. Y estoy configurando páginas de error personalizadas en mi web.config. Realmente prefiero usar la opción de código subyacente, pero parece que no puedo hacer que funcione sin poner un código en línea de pirateo en el diseño / diseño.

Cañón de Bobby
fuente
¿Qué indica el navegador? Utilizo el complemento Header Spy para Firefox.
Bobby Cannon
Respuesta del espía del encabezado: HTTP / 1.1 404 no encontrado Fecha: dom., 07 de diciembre de 2008 06:21:20 GMT
Ryan Cook
¿Estás usando una página maestra? Quizás sea eso. Probaré una página sin usar una página maestra ...
Bobby Cannon
No, no lo estaba, pero también puedo hacer una comprobación rápida, lo intentaré con uno.
Ryan Cook
¡Sí, eso es todo! La página maestra provocó un 200 OK
Ryan Cook

Respuestas:

72

Solución:

Resultó que el problema era el uso de la página maestra. Lo hice funcionar configurando el código de estado más adelante en el ciclo de vida de las páginas, obviamente, la representación de la página maestra lo estaba restableciendo, así que anulé el método de representación y lo configuré después de que se completó la representación.

protected override void Render(HtmlTextWriter writer)
{
    base.Render(writer);
    Response.StatusCode = 404;
}

Se podría trabajar más para averiguar exactamente cuándo la página maestra establece el estado, pero eso se lo dejo a usted.


Publicación original:

Pude hacer que una aplicación web de prueba funcionara bien, bueno, al menos mostró la página de error personalizada y devolvió un código de estado 404. No puedo decirte qué le pasa a tu aplicación, pero puedo decirte lo que hice:

1) Editó web.config para errores personalizados:

<customErrors mode="On">
  <error statusCode="404" redirect="404.aspx"/>
</customErrors>

2) Se agregó una página 404.aspx y se estableció el código de estado en 404.

public partial class _04 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.StatusCode = 404;
    }
}

Eso es todo, si voy a cualquier extensión de página que es procesada por Asp.Net y no existe, mi registro de violinista muestra claramente un 404, aquí está el encabezado:

HTTP/1.1 404 Not Found
Server: Microsoft-IIS/5.1
Date: Sun, 07 Dec 2008 06:04:13 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 533

Ahora, si voy a una página que no está procesada por Asp.Net, como un archivo htm, la página personalizada no se muestra y se muestra el 404 que está configurado por IIS.

Aquí hay una publicación que incluye algunos detalles más que pueden ser de utilidad para usted y su problema, mi prueba redirige a la nueva página, por lo que la URL del archivo solicitado se pierde prácticamente (excepto que está en la cadena de consulta) .

Páginas de error personalizadas de Google 404 y .NET

Respuesta del espía del encabezado:

HTTP/1.1 404 Not Found
Date: Sun, 07 Dec 2008 06:21:20 GMT
Ryan Cook
fuente
4
Header Spy es un complemento de Header Spy para Firefox
Kiquenet
¿Cómo funciona esto para las .htmlpáginas de error personalizadas estáticas ?
ebyrob
28

Tuve un problema similar: quiero mostrar una página personalizada como 404 (que es ASPX) y funcionó bien en localhost, pero tan pronto como un visitante remoto se conectara, obtendrían el IIS 404 genérico.

La solución a esto fue agregar

Response.TrySkipIisCustomErrors = true;

Antes de cambiar Response.StatusCode.

Encontrado a través de Rick Strahl http://www.west-wind.com/weblog/posts/745738.aspx

Gary
fuente
12

La solución de IIS 7 es simplemente agregar esto a su archivo web.config:

<system.webServer>
  <httpErrors existingResponse="Replace">
    <remove statusCode="500" subStatusCode="-1" />
    <remove statusCode="404" subStatusCode="-1" />
    <error statusCode="404" prefixLanguageFilePath="" path="404.htm" responseMode="File" />
    <error statusCode="500" prefixLanguageFilePath="" path="500.htm" responseMode="File" />
  </httpErrors>
</system.webServer>

http://forums.asp.net/t/1563128.aspx/1

Nick D
fuente
3
¡Trabajó para mi! La única solución aquí que funcionó, probablemente debido a la versión como nota ... Tenga en cuenta: solo puede usar archivos .htm estáticos con esta solución.
squarecandy
11

Intente llamar a Response.End () para omitir la representación ...

Response.Status = "404 Not Found";
Response.StatusCode = 404;
Response.End();
return;
Jason Goemaat
fuente
9

Después de muchas pruebas y solución de problemas, parece que ciertos proveedores de alojamiento pueden interferir con el código de retorno. Pude solucionar esto aplicando un "truco" en el contenido.

<%
// This code is required for host that do special 404 handling...
Response.Status = "404 Not Found";
Response.StatusCode = 404;
%>

Esto permitirá que la página devuelva el código de retorno correcto pase lo que pase.

Cañón de Bobby
fuente
1

Pude solucionar este problema usando la siguiente configuración en formularios web asp.net usando .NET 3.5.

El patrón que implementé omite la solución de redireccionamiento personalizado de .NET en web.config, ya que escribí el mío para manejar todos los escenarios con el código de estado HTTP correcto en el encabezado.

Primero, la sección customErrors de web.config se ve así:

<customErrors mode="RemoteOnly" defaultRedirect="~/error.htm" />

Esta configuración garantiza que el modo CustomErrors esté activado, una configuración que necesitaremos más adelante, y proporciona una opción de error de todo lo demás para el defaultRedirect de error.htm. Esto será útil cuando no tenga un controlador para el error específico o si hay algo parecido a una conexión de base de datos rota.

En segundo lugar, aquí está el evento de error global asax:

protected void Application_Error(object sender, EventArgs e)
    {
       HandleError();
    }

    private void HandleError()
    {
        var exception = Server.GetLastError();
        if (exception == null) return;

        var baseException = exception.GetBaseException();

        bool errorHandled = _applicationErrorHandler.HandleError(baseException);
        if (!errorHandled) return;


        var lastError = Server.GetLastError();
    if (null != lastError && HttpContext.Current.IsCustomErrorEnabled)
    {
        Elmah.ErrorSignal.FromCurrentContext().Raise(lastError.GetBaseException());
        Server.ClearError();
    }
    }

Este código transfiere la responsabilidad de manejar el error a otra clase. Si el error no se maneja y CustomErrors está activado, eso significa que tenemos un caso en el que estamos en producción y de alguna manera no se ha manejado un error. Lo borraremos aquí para evitar que el usuario lo vea, pero inicie sesión en Elmah para que sepamos qué está pasando.

La clase applicationErrorHandler se ve así:

public bool HandleError(Exception exception)
        {
            if (exception == null) return false;

            var baseException = exception.GetBaseException();

            Elmah.ErrorSignal.FromCurrentContext().Raise(baseException);

            if (!HttpContext.Current.IsCustomErrorEnabled) return false;

            try
            {

                var behavior = _responseBehaviorFactory.GetBehavior(exception);
                if (behavior != null)
                {
                    behavior.ExecuteRedirect();
                    return true;
                }
            }
            catch (Exception ex)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
            }
            return false;
        }

Esta clase esencialmente usa el patrón de comando para ubicar el controlador de errores apropiado para el tipo de error que se emite. Es importante usar Exception.GetBaseException () en este nivel, porque casi todos los errores se incluirán en una excepción de nivel superior. Por ejemplo, si hace "lanzar una nueva System.Exception ()" desde cualquier página aspx, se recibirá una HttpUnhandledException en este nivel, no una System.Exception.

El código de "fábrica" ​​es simple y tiene este aspecto:

public ResponseBehaviorFactory()
    {
        _behaviors = new Dictionary<Type, Func<IResponseBehavior>>
                        {
                            {typeof(StoreException), () => new Found302StoreResponseBehavior()},
                            {typeof(HttpUnhandledException), () => new HttpExceptionResponseBehavior()},
                            {typeof(HttpException), () => new HttpExceptionResponseBehavior()},
                            {typeof(Exception), () => new Found302DefaultResponseBehavior()}
                        };
    }

    public IResponseBehavior GetBehavior(Exception exception)
    {                                                                               
        if (exception == null) throw new ArgumentNullException("exception");

        Func<IResponseBehavior> behavior;
        bool tryGetValue = _behaviors.TryGetValue(exception.GetType(), out behavior);

        //default value here:
        if (!tryGetValue)
            _behaviors.TryGetValue(typeof(Exception), out behavior);

        if (behavior == null)
            Elmah.ErrorSignal.FromCurrentContext().Raise(
                new Exception(
                    "Danger! No Behavior defined for this Exception, therefore the user might have received a yellow screen of death!",
                    exception));
        return behavior();
    }

Al final, tengo una configuración de esquema de manejo de errores extensible. En cada uno de los "comportamientos" que se definen, tengo una implementación personalizada para el tipo de error. Por ejemplo, se inspeccionará una excepción Http para el código de estado y se manejará adecuadamente. Un código de estado 404 requerirá un Server.Transfer en lugar de un Request.Redirect, junto con el código de estado apropiado escrito en el encabezado.

Espero que esto ayude.

Letgetsilly
fuente
0

Puede utilizar el siguiente código:

 Response.TrySkipIisCustomErrors = True
 Response.Status = "404 Not Found"
 Response.AddHeader("Location", "{your-path-to-your-404-page}")
Rami Zebian
fuente