ASP.NET Custom 404 Devolver 200 OK En lugar de 404 No encontrado


Después de intentar configurar mi sitio para Google Webmaster Tools, encontré que mi ASP.NET la página 404 no estaba devolviendo el código de estado 404. Se muestra la página personalizada correcta y le dice al navegador que todo está bien. Esto es considerar un 404 suave o 404 falso. A Google no le gusta esto. Así que encontré muchos artículos sobre el tema, pero la solución que quiero 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 del página personalizada 404.

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 está usando una página maestra. Y estoy configurando páginas de error personalizadas en mi web.config. Realmente preferiría usar la opción code behind, pero parece que no puedo hacer que funcione sin poner un código en línea hack en el diseño / diseño.

Author: Bobby Cannon, 2008-12-07

6 answers

Solución:

Resultó que el problema era el uso de la página maestra. Conseguí que funcionara configurando el código de estado más adelante en el ciclo de vida de las páginas, obviamente el renderizado de la página maestra lo reiniciaba, así que anulé el método de renderizado y lo establecí después de que el renderizado se completara.

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

Se podría hacer más trabajo para saber exactamente cuándo la página maestra está configurando el estado, pero te dejaré eso a ti.


Mensaje original:

I fue capaz de 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 lo que está mal con tu aplicación, pero puedo decirte lo que hice:

1) Editó la web.configuración para errores personalizados:

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

2) Añadido un 404.página aspx y establecer el código de estado a 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 se procesa por Asp.Net y no existe, mi registro violinista claramente muestra 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 es procesada por Asp.Net, como un archivo htm, la página personalizada no se muestra y se muestra el 404 configurado por IIS.

Aquí hay un post que entra en algunos detalles más que pueden ser de utilidad para usted y su problema, mi prueba hace un redireccionamiento a la nueva página por lo que la url del archivo solicitado es bastante perdido (excepto su en la cadena de consulta).

Google 404 y. NET Personalizado Páginas de error

Header Spy Response:

HTTP/1.1 404 Not Found
Date: Sun, 07 Dec 2008 06:21:20 GMT
 69
Author: Ryan Cook,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:00

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

La solución a esto fue agregar

Response.TrySkipIisCustomErrors = true;

Antes de cambiar la Respuesta.Código de estado.

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

 27
Author: gary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-22 23:28:31

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

<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

 12
Author: Nick D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-03 08:05:06

Intenta llamar a Respuesta.End() para omitir el renderizado...

Response.Status = "404 Not Found";
Response.StatusCode = 404;
Response.End();
return;
 10
Author: Jason Goemaat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-22 00:06:05

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 evitar esto aplicando un "hackeo" 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 sin importar qué.

 6
Author: Bobby Cannon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-08 01:54:36

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

El patrón que he implementado omite la solución de redirección personalizada de.NET en la web.config como he escrito mi propio para manejar todos los escenarios con el código de estado HTTP correcto en el encabezado.

Primero, la web.la sección customErrors de 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 un opción all-else-fails para el defaultRedirect de error.htm. Esto será útil cuando no tengo un controlador para el error específico, o hay algo en las líneas de una conexión de base de datos rota.

Segundo, aquí está el evento de error global de 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 está pasando 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 un error no ha sido manejado. Lo limpiaremos 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 utiliza esencialmente el patrón de comando para localizar el controlador de errores apropiado para el tipo de error que se emite. Es importante usar la excepción.GetBaseException() en este nivel, porque casi todos los errores serán envueltos en una excepción de nivel superior. Por ejemplo, haciendo "lanza un nuevo Sistema.Exception () " desde cualquier página aspx resultará en que se reciba una HttpUnhandledException en este nivel, no un Sistema.Salvedad.

El código "factory" es simple y se ve así:

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, una excepción Http será inspeccionada para el código de estado y manejada apropiadamente. A 404 status el código requerirá un servidor.Transferencia en lugar de una solicitud.Redireccionar, junto con el código de estado apropiado escrito en el encabezado.

Espero que esto ayude.

 1
Author: letsgetsilly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-20 17:32:55