webentwicklung-frage-antwort-db.com.de

ASP.NET Custom 404, das 200 OK anstelle von 404 Not Found zurückgibt

Nach dem Versuch, meine Website für Google Webmaster-Tools einzurichten, stellte ich fest, dass meine benutzerdefinierte ASP.NET 404-Seite den 404-Statuscode nicht zurückgab. Es wurde die richtige benutzerdefinierte Seite angezeigt und dem Browser mitgeteilt, dass alles in Ordnung ist. Dies ist ein Soft 404 oder ein False 404. Google gefällt das nicht. Ich fand also viele Artikel zu diesem Thema, aber die gewünschte Lösung schien nicht zu funktionieren.

Die Lösung, die ich arbeiten möchte, ist das Hinzufügen der folgenden zwei Zeilen zum Code hinter der Page Load-Methode der benutzerdefinierten 404-Seite.

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

Das geht nicht. Die Seite gibt weiterhin 200 OK zurück. Ich fand jedoch, dass, wenn ich den folgenden Code in den Entwurfscode fest einprogrammiere, es richtig funktioniert.

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

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

 ... Much more code ...

</asp:content>

Die Seite verwendet eine Masterseite. Und ich konfiguriere benutzerdefinierte Fehlerseiten in meiner web.config. Ich würde wirklich lieber den Code hinter der Option verwenden, aber ich kann es scheinbar nicht zum Laufen bringen, ohne den Hack-Inline-Code in das Design/Layout einzufügen.

77
Bobby Cannon

Lösung:

Es stellte sich heraus, dass das Problem die Verwendung der Masterseite war. Ich habe es zum Laufen gebracht, indem ich den Statuscode später im Lebenszyklus der Seiten festgelegt habe. Offensichtlich hat das Rendern der Masterseite das Zurücksetzen bewirkt. Ich habe die Rendermethode überschrieben und es festgelegt, nachdem das Rendern abgeschlossen war.

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

Es könnte noch mehr Arbeit geleistet werden, um herauszufinden, wann genau die Masterseite den Status setzt, aber das überlasse ich Ihnen.


Ursprünglicher Beitrag:

Ich konnte eine Test-Web-App zum Laufen bringen. Zumindest wurde die benutzerdefinierte Fehlerseite angezeigt und ein 404-Statuscode zurückgegeben. Ich kann dir nicht sagen, was mit deiner App los ist, aber ich kann dir sagen, was ich getan habe:

1) Die web.config für benutzerdefinierte Fehler bearbeitet:

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

2) Fügen Sie eine 404.aspx-Seite hinzu und setzen Sie den Statuscode auf 404.

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

Wenn ich zu einer Seitenerweiterung gehe, die von Asp.Net verarbeitet wird und nicht vorhanden ist, zeigt mein Fiddler-Protokoll eindeutig eine 404 an. Hier ist die Kopfzeile:

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

Wenn ich jetzt zu einer Seite gehe, die nicht von Asp.Net verarbeitet wird, wie z. B. einer HTML-Datei, wird die benutzerdefinierte Seite nicht angezeigt und die 404, die von IIS konfiguriert wurde, wird angezeigt.

Hier ist ein Beitrag, der einige Details behandelt, die für Sie und Ihr Problem von Nutzen sein können. Mein Test führt eine Weiterleitung auf die neue Seite durch, sodass die URL der angeforderten Datei so gut wie verloren geht (außer in der Abfragezeichenfolge). .

Benutzerdefinierte Fehlerseiten für Google 404 und .NET

Antwort des Headerspions:

HTTP/1.1 404 Not Found
Date: Sun, 07 Dec 2008 06:21:20 GMT
71
Ryan Cook

Ich hatte ein ähnliches Problem. Ich möchte eine benutzerdefinierte Seite als 404 (das ist ASPX) anzeigen und sie funktionierte auf localhost einwandfrei, aber sobald ein entfernter Besucher eine Verbindung herstellte, bekamen sie das generische IIS 404) .

Die Lösung hierfür war hinzuzufügen

Response.TrySkipIisCustomErrors = true;

Vor dem Ändern des Response.StatusCode.

Gefunden über Rick Strahl http://www.west-wind.com/weblog/posts/745738.aspx

27
gary

Die IIS 7-Lösung besteht darin, Folgendes zu Ihrer web.config-Datei hinzuzufügen:

<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
Nick D

Versuchen Sie, Response.End () aufzurufen, um das Rendern zu überspringen ...

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

Nach vielen Tests und Fehlerbehebungen kann es vorkommen, dass bestimmte Hosting-Anbieter den Rückkehrcode stören. Ich konnte dies umgehen, indem ich einen "Hack" in den Inhalt einfügte.

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

Auf diese Weise kann die Seite den korrekten Rückkehrcode zurückgeben, egal was passiert.

7
Bobby Cannon

Ich konnte dieses Problem umgehen, indem ich das folgende Setup in asp.net-Webforms unter Verwendung von .NET 3.5 verwendete.

Das von mir implementierte Muster umgeht die benutzerdefinierte Umleitungslösung von .NET in der Datei web.config, da ich ein eigenes geschrieben habe, um alle Szenarien mit dem richtigen HTTP-Statuscode im Header zu behandeln.

Zunächst sieht der Abschnitt customErrors der web.config folgendermaßen aus:

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

Dieses Setup stellt sicher, dass der CustomErrors-Modus aktiviert ist, eine Einstellung, die wir später benötigen, und bietet eine Option für alle anderen Fehler für das defaultRedirect von error.htm. Dies ist praktisch, wenn ich keinen Handler für den bestimmten Fehler habe oder wenn eine unterbrochene Datenbankverbindung vorliegt.

Zweitens ist hier das globale asax-Fehlerereignis:

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();
    }
    }

Dieser Code gibt die Verantwortung für die Behandlung des Fehlers an eine andere Klasse weiter. Wenn der Fehler nicht behoben und CustomErrors aktiviert ist, bedeutet dies, dass wir einen Fall haben, in dem wir in Produktion sind und ein Fehler nicht behoben wurde. Wir werden es hier löschen, um den Benutzer daran zu hindern, es zu sehen, aber melden Sie es in Elmah an, damit wir wissen, was los ist.

Die applicationErrorHandler-Klasse sieht folgendermaßen aus:

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;
        }

Diese Klasse verwendet im Wesentlichen das Befehlsmuster, um den geeigneten Fehlerbehandler für den Typ des ausgegebenen Fehlers zu finden. Es ist wichtig, Exception.GetBaseException () auf dieser Ebene zu verwenden, da fast jeder Fehler in eine Ausnahme höherer Ebene eingeschlossen wird. Wenn Sie beispielsweise "throw new System.Exception ()" von einer beliebigen aspx-Seite aus ausführen, wird auf dieser Ebene eine HttpUnhandledException empfangen, keine System.Exception.

Der "Fabrik" Code ist einfach und sieht so aus:

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();
    }

Am Ende habe ich ein erweiterbares Fehlerbehandlungsschema eingerichtet. In jedem der definierten "Verhaltensweisen" habe ich eine benutzerdefinierte Implementierung für den Fehlertyp. Beispielsweise wird eine HTTP-Ausnahme auf den Statuscode überprüft und entsprechend behandelt. Ein 404-Statuscode erfordert einen Server.Transfer anstelle eines Request.Redirect sowie den entsprechenden Statuscode, der im Header angegeben ist.

Hoffe das hilft.

1
letsgetsilly