IIS7 Überschreibt customErrors beim Festlegen von Response.StatusCode?

98

Ich habe hier ein komisches Problem. Jeder weiß, dass Sie, wenn Sie den customErrorsAbschnitt von web.config verwenden , um eine benutzerdefinierte Fehlerseite zu erstellen, die entsprechende Einstellung vornehmen sollten Response.StatusCode. Wenn ich beispielsweise eine benutzerdefinierte 404-Seite erstelle und sie 404.aspx nenne, kann ich <% Response.StatusCode = 404 %>den Inhalt einfügen, damit er einen echten 404-Statusheader hat.

Folge mir so weit? Gut. Versuchen Sie dies jetzt auf IIS7. Ich kann es nicht zum Laufen bringen, Punkt. Wenn dies Response.StatusCodeauf der benutzerdefinierten Fehlerseite festgelegt ist, scheint IIS7 die benutzerdefinierte Fehlerseite vollständig zu überschreiben und zeigt eine eigene Statusseite an (falls Sie eine konfiguriert haben).

Hat jemand anderes dieses Verhalten gesehen und weiß vielleicht auch, wie man es umgeht? Es hat unter IIS6 funktioniert, daher weiß ich nicht, warum sich die Dinge geändert haben.

Hinweis: Dies ist nicht dasselbe wie das Problem in ASP.NET Custom 404, das 200 OK anstelle von 404 Not Found zurückgibt

Nikolaus
quelle
Ich hatte die gleiche Frage. Bereits hier beantwortet http://stackoverflow.com/questions/347281/asp-net-custom-404-returning-200-ok-instead-of-404-not-found .
Bobby Cannon
Bobby, ich habe diese Frage tatsächlich gefunden und ausprobiert, aber das Problem wurde dadurch nicht behoben. Aber danke.
Nicholas
Ich möchte darauf hinweisen, dass dieses Problem auch beim Wechsel von Classic zu Integrated Pipeine auftritt. Ich habe die @ PavelChuchuva-Lösung verwendet (die @ RickStrahl-Lösung funktioniert auch). Ich vermute, das "Passthrough" in Classic erfolgt automatisch, in Integrated wird die globale Fehlerseitenbehandlung des Servers übernommen.
sonjz

Antworten:

116

Setzen Sie im Abschnitt system.webServer / httpErrors die vorhandene Antwort auf PassThrough:

  <system.webServer>
    <httpErrors existingResponse="PassThrough" />
  </system.webServer>

Der Standardwert der vorhandenenResponse-Eigenschaft ist Auto:

Auto weist das benutzerdefinierte Fehlermodul an, das Richtige zu tun. Der tatsächliche Fehlertext, der von Clients angezeigt wird, hängt vom Wert des im IHttpResponse::GetStatusAufruf zurückgegebenen fTrySkipCustomErrors ab . Wenn fTrySkipCustomErrors auf true gesetzt ist, lässt das benutzerdefinierte Fehlermodul die Antwort durch. Wenn es jedoch auf false gesetzt ist, ersetzt das benutzerdefinierte Fehlermodul den Text durch seinen eigenen Text.

Weitere Informationen: Was Sie vom benutzerdefinierten IIS7-Fehlermodul erwarten können

Pavel Chuchuva
quelle
3
Beachten Sie, dass das Festlegen der vorhandenen Antwort auf PassThrough zu Nebenwirkungen führen kann. Bitte beherrschen Sie den von Pavel bereitgestellten Link, bevor Sie Änderungen vornehmen.
Lex Li
Ist <httpErrors existingResponse="PassThrough" />gleichwertig Response.TrySkipIisCustomErrorsoder verhalten sie sich anders?
Asbjørn Ulsberg
1
@sbjornu Sie erreichen dasselbe, aber mit Response.TrySkipIisCustomErrorsIhnen erhalten Sie eine bessere Kontrolle darüber, wann benutzerdefinierte IIS-Fehler angezeigt werden sollen.
Pavel Chuchuva
Vielen Dank, ich habe viele Informationen über response.tryskipiiscustomerrors gesehen, aber nicht so sehr über bestehende Antworten.
HBCondo
Ich habe ein Problem mit benutzerdefinierten Fehlerseiten gelöst, die auf meinem Webhost, auf dem IIS7 ausgeführt wird, nicht funktionieren, indem ich einfach existierende Antwort = "Auto" gesetzt habe. Dies war sehr überraschend, da der Artikel auf Ansprüche verweist, die die Standardeinstellung sind. Es ist eindeutig nicht ... oder mein Hosting-Unternehmen hat anderswo den falschen Standard festgelegt, nehme ich an. So oder so hoffe ich, dass das jemandem ein paar Stunden erspart: \
Eric Sassaman
80

Der einfachste Weg, um das Verhalten konsistent zu machen, besteht darin, den Fehler zu löschen und Response.TrySkipIisCustomErrors zu verwenden und auf true zu setzen. Dadurch wird die globale IIS-Fehlerseitenbehandlung innerhalb Ihrer Seite oder der globalen Fehlerbehandlungsroutine in Application_Error überschrieben.

Server.ClearError();
Response.TrySkipIisCustomErrors = true;

Normalerweise sollten Sie dies in Ihrem Application_Error-Handler tun, der alle Fehler behandelt, die Ihre Application Error-Handler nicht abfangen.

Weitere Informationen finden Sie in diesem Blogbeitrag: http://www.west-wind.com/weblog/posts/745738.aspx

Rick Strahl
quelle
2
Dies funktioniert auch bei mir nicht (IIS8), und der Rat scheint nicht mit dem OP übereinzustimmen (vorausgesetzt, ich lese ihn richtig). Ich möchte, dass die customErrorin Web.config konfigurierte ausgelöst wird. Mit Response.TrySkipIisCustomErrors = truebekomme ich das gleiche Verhalten: Die hässliche vom Server generierte Fehlerseite wird angezeigt. Wenn es auf falsenichts eingestellt ist, passiert nichts - ein leeres Browserfenster.
Shawn South
Hat gut funktioniert für mich! Während die Einstellung, die Pavel Chuchuva in seiner Antwort erwähnt, ebenfalls funktionierte, hatte sie einige Nebenwirkungen, die andere Probleme verursachten. Mit dieser Einstellung kann ich die IIS-Fehlerüberschreibung in dem gewünschten Szenario überspringen und das Verhalten für alles andere beibehalten.
Kevin Tighe
Hat in Azure für mich gut funktioniert. Server-HeaderServer:Microsoft-IIS/8.5 X-AspNet-Version:4.0.30319 X-AspNetMvc-Version:5.2 X-Powered-By:ASP.NET
Oxfn
Ich muss immer noch festlegen, customErrors mode="Off"dass dies funktioniert. Wenn ich das mache, funktioniert die httpErrors existierende Antwort = "Auto" (Standardeinstellung) für mich ordnungsgemäß, wenn ich den Code in dieser Antwort verwende.
AaronLS
11

Behoben: Es stellt sich heraus, dass "Detaillierte Fehler" aktiviert sein muss, damit IIS7 eine eventuell vorhandene Fehlerseite "durchläuft". Siehe http://forums.iis.net/t/1146653.aspx

Nikolaus
quelle
1
Obwohl diese als Antwort markiert wurde, lohnt es sich meiner Meinung nach, andere Antworten zu lesen, um mehr Einblicke in das Thema zu erhalten.
Lex Li
Auch könnte es gut sein, zu entfernen. HandleErrorAttribute in FilterConfig
Per G
4

Ich bin mir nicht sicher, ob dies von Natur aus ähnlich ist oder nicht, aber ich habe ein Problem gelöst, das an der Oberfläche ähnlich klingt, und hier ist, wie ich damit umgegangen bin.

Zunächst war der Standardwert für existierende Antwort (Auto) in meinem Fall die richtige Antwort, da ich benutzerdefinierte 404, 400 und 500 habe (ich könnte andere erstellen, aber diese drei reichen für meine Arbeit aus). Hier sind die relevanten Abschnitte, die mir geholfen haben.

Aus web.config:

<customErrors mode="Off" />

Und

<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/errors/404.aspx" responseMode="ExecuteURL" />
  <error statusCode="500" path="/errors/500.aspx" responseMode="ExecuteURL" />
  <error statusCode="400" path="/errors/400.aspx" responseMode="ExecuteURL" />
</httpErrors>

Von dort habe ich dies in Application_Error auf global.asax hinzugefügt:

    Response.TrySkipIisCustomErrors = True

Auf jeder meiner benutzerdefinierten Fehlerseiten musste ich den richtigen Antwortstatuscode angeben. In meinem Fall verwende ich eine benutzerdefinierte 404, um Benutzer an verschiedene Bereiche meiner Website zu senden. Daher möchte ich keinen 404-Statuscode zurückgeben, es sei denn, es handelt sich tatsächlich um eine tote Seite.

Jedenfalls habe ich es so gemacht. Hoffe das hilft jemandem.

SEFL
quelle
3

Dieses Problem hat große Kopfschmerzen verursacht. Keiner der zuvor erwähnten Vorschläge allein hat es für mich gelöst, daher schließe ich meine Lösung ein. Für die Aufzeichnung verwendet unsere Umgebung / Plattform:

  • .NET Framework 4
  • MVC 3
  • IIS8 (Workstation) und IIS7 (Webserver)

Insbesondere habe ich versucht, eine HTTP 404-Antwort zu erhalten, die den Benutzer auf unsere benutzerdefinierte 404-Seite umleitet (über die Web.config-Einstellungen).

Zuerst musste mein Code einen werfen HttpException. Die Rückgabe eines NotFoundResultvom Controller hat nicht die gewünschten Ergebnisse erzielt.

throw new HttpException(404, "There is no class with that subject");

Dann musste ich sowohl die customErrorsals auch die httpErrorKnoten in der Web.config konfigurieren.

<customErrors mode="On" defaultRedirect="/classes/Error.aspx">
  <error statusCode="404" redirect="/classes/404.html" />
</customErrors>

...

<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/classes/404.aspx" responseMode="ExecuteURL" />
</httpErrors>

Beachten Sie, dass ich das existingResponseas belassen habe Auto, was sich von der bereitgestellten Lösung @sefl unterscheidet.

Die customErrorsEinstellungen schienen notwendig zu sein, um meine explizit ausgelösten zu verarbeiten HttpException, während der httpErrorsKnoten URLs behandelte, die außerhalb der in Globals.asax.cs angegebenen Routenmuster lagen.

PS Mit diesen Einstellungen musste ich nicht einstellen Response.TrySkipIisCustomErrors

Shawn South
quelle
2

TrySkipIisCustomErrorsist nur ein Teil eines Puzzles. Wenn Sie benutzerdefinierte Fehlerseiten verwenden, aber auch RESTful-Inhalte basierend auf 4xx-Status bereitstellen möchten, liegt ein Problem vor. Das Festlegen der httpErrors.existingResponse von web.config auf "Auto" funktioniert nicht, da .net anscheinend immer einige Seiteninhalte an IIS liefert. Daher führt die Verwendung von "Auto" dazu, dass alle (oder zumindest einige) benutzerdefinierten Fehlerseiten nicht verwendet werden. Die Verwendung von "Ersetzen" funktioniert auch nicht, da die Antwort Ihren http-Statuscode enthält, der Inhalt jedoch leer oder mit einer benutzerdefinierten Fehlerseite gefüllt ist. Und das "PassThrough" schaltet das CEP tatsächlich aus, sodass es nicht verwendet werden kann.

Wenn Sie also CEP in einigen Fällen umgehen möchten (durch Umgehen meine ich, dass Sie den Status 4xx mit einigen Inhalten zurückgeben), benötigen Sie einen zusätzlichen Schritt: Bereinigen Sie den Fehler:

void Application_Error(object sender, EventArgs e)
{
    var httpException = Context.Server.GetLastError() as HttpException;
    var statusCode = httpException != null ? httpException.GetHttpCode() : (int)HttpStatusCode.InternalServerError;

    Context.Server.ClearError();
    Context.Response.StatusCode = statusCode;
}

Wenn Sie also die REST-Antwort (dh 400 - Bad Request) verwenden und Inhalte damit senden möchten, müssen Sie nur TrySkipIisCustomErrorsirgendwo in Aktion festlegen und existingResponseim Abschnitt httpErrors in web.config auf "Auto" setzen. Jetzt:

  • Wenn kein Fehler vorliegt (Aktion gibt 4xx oder 5xx zurück) und ein Teil des Inhalts zurückgegeben wird, wird der CEP nicht verwendet und der Inhalt an den Client übergeben.
  • Wenn ein Fehler auftritt (eine Ausnahme wird ausgelöst), wird der von den Fehlerbehandlungsroutinen zurückgegebene Inhalt entfernt, sodass der CEP verwendet wird.

Wenn Sie den Status mit leerem Inhalt aus Ihrer Aktion zurückgeben möchten, wird dieser als leere Antwort behandelt und CEP wird angezeigt, sodass dieser Code noch verbessert werden kann.

Łukasƨ Fronczyk
quelle
0

Standardmäßig verwendet IIS 7 detaillierte benutzerdefinierte Fehlermeldungen, sodass ich davon ausgehen würde, dass Response.StatusCode 404.XX und nicht nur 404 entspricht.

Sie können IIS7 so konfigurieren, dass es die einfacheren Fehlermeldungscodes verwendet, oder Ihren Code ändern, der die detaillierteren Fehlermeldungen behandelt, die IIS7 bietet.

Weitere Informationen finden Sie hier: http://blogs.iis.net/rakkimk/archive/2008/10/03/iis7-enabling-custom-error-pages.aspx

Weitere Untersuchungen ergaben, dass ich es falsch herum hatte - detaillierte Nachrichten sind nicht standardmäßig aktiviert, aber möglicherweise wurden sie auf Ihrer Box aktiviert, wenn Sie die verschiedenen von Ihnen erwähnten Fehlermeldungen sehen.

nullnvoid
quelle
Response.StatusCode ist eine Ganzzahl, daher sehe ich keine Möglichkeit, einen spezifischeren Code als nur "404" festzulegen. Ich habe IIS7 so konfiguriert, dass benutzerdefinierte Fehlerseiten verwendet / angezeigt werden, wie Ihre URL angibt.
Nicholas
Hmmm ... Leider kann ich im Moment nicht testen, da ich nicht auf meinem Heim-PC bin. Wenn Sie bis dahin keine Lösung haben, werde ich heute Abend einen Blick darauf werfen.
nullnvoid