Der Server kann den Status nicht festlegen, nachdem HTTP-Header an IIS7.5 gesendet wurden

70

Manchmal bekomme ich in meiner Produktionsumgebung eine Ausnahme:

  • Prozessinformationen
    • Prozess-ID: 3832
    • Prozessname: w3wp.exe
    • Kontoname: NT AUTHORITY \ NETWORK SERVICE
  • Ausnahmeinformationen
    • Ausnahmetyp: System.Web.HttpException
    • Ausnahmemeldung: Der Server kann den Status nicht festlegen, nachdem HTTP-Header gesendet wurden.
  • Anfrage Informationen
    • URL anfordern: http://www.myulr.pl/logon
    • Anforderungspfad: / logon
    • Benutzerhostadresse: 10.11.9.1
    • Benutzer: user001
    • Ist authentifiziert: True
    • Authentifizierungstyp: Formulare
    • Name des Thread-Kontos: NT AUTHORITY \ NETWORK SERVICE
  • Thread-Informationen
    • Thread-ID: 10
    • Name des Thread-Kontos: NT AUTHORITY \ NETWORK SERVICE
    • Imitiert: Falsch
Stack trace: at System.Web.HttpResponse.set_StatusCode(Int32 value) at  
System.Web.HttpResponseWrapper.set_StatusCode(Int32 value) at  
System.Web.Mvc.HandleErrorAttribute.OnException(ExceptionContext filterContext) at  
System.Web.Mvc.ControllerActionInvoker.InvokeExceptionFilters(ControllerContext controllerContext, IList(1) filters, Exception exception) at  
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) at System.Web.Mvc.Controller.ExecuteCore() at  
System.Web.Mvc.MvcHandler.<>c__DisplayClass8.<BeginProcessRequest>b__4() at  
System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0() at  
System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8(1).<BeginSynchronous>b__7(IAsyncResult _) at  
System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult(1).End() at   
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) at  
System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at  
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& ompletedSynchronously) 

Ich habe diesen Fehler in meiner Testumgebung nicht bemerkt. Was soll ich überprüfen?

Ich verwende ASP.NET MVC 2 (Release Candidate 2)

marcinn
quelle
Das passiert mir auch. Der Fehler kommt wie in Ihrem Fall aus dem HandleErrorAttribute.
Gabe Moothart
1
Konnten Sie dieses Problem lösen?
Azho KG
3
Ich hatte das gleiche Problem seit dem Wechsel zu MVC 2. Auch beim Setzen von Cookies tritt ein ähnlicher Fehler auf - kann nicht auftreten, nachdem Header gesendet wurden. Ich bin gespannt auf die Antwort. In meinem Fall scheint der Wechsel zwischen http / https eine Rolle zu spielen.
Matt Sherman
3
Ich fand, dass ich versuchte, Benutzer in Actionfilter (OnActionExecuting) umzuleiten - dies war ein Problem
marcinn

Antworten:

61

Ich werde Vagrant in der Sache weitgehend zustimmen:

  1. Ihre Aktion wurde ausgeführt und Markup in den Antwortstrom geschrieben
  2. Der Stream war ungepuffert und zwang die Antwortheader, geschrieben zu werden, bevor das Markup-Schreiben beginnen konnte.
  3. In Ihrer Ansicht ist ein Laufzeitfehler aufgetreten
  4. Der Ausnahmebehandler versucht zunächst, den Statuscode auf einen anderen Wert als 200 festzulegen
  5. Schlägt fehl, weil die Header bereits gesendet wurden.

Wenn ich mit Vagrant nicht einverstanden bin, ist das Mittel "Keine Fehler beim Binden verursachen" - es können immer noch Laufzeitfehler beim Anzeigen der Bindung auftreten, z. B. Nullreferenzausnahmen.

Eine bessere Lösung hierfür ist es, dies sicherzustellen Response.BufferOutput = true; keine Bytes an den Antwortstrom gesendet werden. zB in Ihrer Controller-Aktion oder On_Begin_Request in der Anwendung. Dies ermöglicht das Setzen von Serverübertragungen, Cookies / Headern usw. bis hin zur natürlichen Beendigung der Antwort oder zum Aufruf von end / flush.

Stellen Sie natürlich auch sicher, dass der Puffer nicht weiter unten im Stapel geleert / auf false gesetzt wird.

MSDN-Referenz: HttpResponse.BufferOutput

stephbu
quelle
1
Ich erhalte den gleichen Fehler, aber in meinem Fall passiert es, wenn ich versuche, eine untergeordnete Aktion aufzurufen. Ich habe versucht, Response.BufferOutput = truezu Beginn der übergeordneten Aktion zu setzen, aber das hat nicht geholfen. Irgendwelche Ideen?
Samo
Samo, irgendwo früher in Ihrem Code schreibt etwas Bytes in den Antwortstrom. Stellen Sie die Pufferung mu zu Beginn der Anforderungsverarbeitung ein, z. B. bevor Sie Ihre Aktion in Ihrem Controller beginnen lassen.
Stephbu
Wie HttpResponse.BufferOutputin MVC Controller verwenden?
Kiquenet
In meinem Index Action Controller habe ich: [HttpPost]und[ValidateAntiForgeryToken]
Kiquenet
(Angenommen, Sie sprechen von System.Web.Mvc.Controller.) Der Controller verfügt über einen Antwort-Accessor, der den Zugriff auf das HttpResponse-Objekt für den aktuellen HTTP-Anforderungskontext ermöglicht. So dass in Controller-Methoden Folgendes gültig ist:this.Response.BufferOutput
stephbu
50

Nur um die obigen Antworten zu ergänzen. Ich hatte das gleiche Problem, als ich ASP.Net MVC zum ersten Mal verwendete und während einer Controller-Aktion eine Response.Redirect ausführte:

Response.Redirect("/blah", true);

Anstatt eine Response.RedirectAktion zurückzugeben, hätte ich Folgendes zurückgeben sollen RedirectAction:

return Redirect("/blah");
Doug
quelle
1
Genau das habe ich auch getan. Danke für die Fehlerbehebung.
Bryan Legend
1
Danke, ich habe das gleiche in meinem Filter gemacht. Es wurde geändert und dies wurde behoben ... // URL-Helfer zum Generieren einer Weiterleitungs-URL. UrlHelper urlHelper = neuer UrlHelper (filterContext.RequestContext); filterContext.Result = new RedirectResult (urlHelper.Action (ActionNames.Index, ControllerNames.CustomerSearch, new {Area = ""})); // am Ende base.OnActionExecuting (filterContext);
Lernen ...
2
Ich hatte ein ähnliches Problem mit dem .NET CAS-Client, und diese Antwort hat mich auf mein Problem aufmerksam gemacht. Ich habe im Wesentlichen eine Antwort 'zweimal' zurückgegeben und CasAuthentication.SingleSignOut () aufgerufen. gefolgt von einer RedirectToAction (). Das macht natürlich keinen Sinn - wie kann man zweimal umleiten, oder? Aber ich habe es damals nicht bemerkt. Ich habe meinen LogOut-Aktionstyp von ActionResult in void geändert, die Umleitung entfernt und das Problem behoben. Vielen Dank!
Pandincus
16

Der HTTP-Server sendet den Antwortheader erst dann an den Client zurück, wenn Sie entweder einen Fehler angeben oder mit dem Senden von Daten beginnen. Wenn Sie anfangen, Daten an den Client zurückzusenden, muss der Server zuerst den Antwortkopf (der den Statuscode enthält) senden. Sobald der Header gesendet wurde, können Sie natürlich keinen Statuscode mehr in den Header einfügen.

Hier ist das übliche Problem. Sie starten die Seite und senden einige erste Tags (dh <head>). Der Server sendet diese Tags dann an den Client, nachdem er zuerst den HTTP-Antwortheader mit dem angenommenen SUCCESS-Status gesendet hat. Jetzt beginnen Sie mit der Arbeit am Fleisch der Seite und entdecken ein Problem. Sie können zu diesem Zeitpunkt keinen Fehler senden, da der Antwortheader, der den Fehlerstatus enthalten würde, bereits gesendet wurde.

Die Lösung lautet wie folgt: Bevor Sie Inhalte generieren, überprüfen Sie, ob Fehler auftreten. Erst dann, wenn Sie sicher sind, dass es keine Probleme gibt, können Sie mit dem Senden von Inhalten wie dem Tag beginnen.

In Ihrem Fall haben Sie anscheinend eine Anmeldeseite, auf der eine POST-Anforderung aus einem Formular verarbeitet wird. Sie werfen wahrscheinlich etwas anfängliches HTML aus und prüfen dann, ob der Benutzername und das Passwort gültig sind. Stattdessen sollten Sie zuerst den Benutzer / das Kennwort authentifizieren, bevor Sie überhaupt HTML generieren .

Landstreicher
quelle
11

Ich hatte das gleiche Problem mit der Einstellung StatusCodeund dann Response.Endin der HandleUnauthorizedRequestMethode vonAuthorizeAttribute

var ctx = filterContext.HttpContext;
ctx.Response.StatusCode = (int)HttpStatusCode.Forbidden;
ctx.Response.End();

Wenn Sie .NET 4.5+ verwenden, fügen Sie diese Zeile zuvor hinzu Response.StatusCode

filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

Wenn Sie .NET 4.0 verwenden, versuchen Sie es mit SuppressFormsAuthenticationRedirectModule .

VahidN
quelle
10

Wie wäre es, dies zu überprüfen, bevor Sie die Weiterleitung durchführen:

if (!Response.IsRequestBeingRedirected)
{
   //do the redirect
}
Sandeep
quelle
3

Sie versuchen tatsächlich, eine Seite umzuleiten, auf die eine Antwort zu werfen ist. Sie behalten also zuerst die Informationen, die Sie response.buffer = trueam Anfang der Seite in einen Puffer geworfen haben, und leeren sie dann, wenn dies erforderlich ist. response.flushDieser Fehler wird behoben

hema
quelle
1

Ich erinnere mich an den Teil dieser Ausnahme: "Header-Informationen können nicht geändert werden - Header werden bereits gesendet von" in PHP. Es trat auf, wenn die Header bereits in der Umleitungsphase gesendet wurden und eine andere Ausgabe generiert wurde, z.

Echo "Hallo"; Header ("Speicherort: http://stackoverflow.com ");

Verzeihen Sie mir und korrigieren Sie mich, wenn ich falsch liege, aber ich lerne immer noch MS Technologies und habe versucht zu helfen.

Adil Mehmood
quelle
1

Ich entschuldige mich, aber ich füge meine 2 Cent zum Thread hinzu, nur für den Fall, dass jemand das gleiche Problem hat.

  • Ich habe die Formularauthentifizierung in meiner MVC-App verwendet
  • Einige Controller-Aktionen waren jedoch "anonym", dh nicht authentifizierten Benutzern gestattet
  • Manchmal möchte ich bei diesen Aktionen immer noch, dass Benutzer unter bestimmten Bedingungen zum Anmeldeformular umgeleitet werden
  • um das zu tun - ich habe dies in meiner Aktionsmethode: return new HttpStatusCodeResult(401)- und ASP.NET ist super nett, dies zu erkennen, und es leitet den Benutzer zur Anmeldeseite weiter! Magie, richtig? Es hat sogar den richtigen ReturnUrlParameter usw.

Aber sehen Sie, wo ich hierher komme? Ich gebe 401 zurück . Und ASP.NET leitet den Benutzer weiter. Welches ist im Wesentlichen Rückgabe 302 . Ein Statuscode wird durch einen anderen ersetzt.

Und einige IIS-Server (nur einige!) Lösen diese Ausnahme aus. Einige tun es nicht. - Ich habe es nicht auf meinem Test serevr, nur auf meinem Produktionsserver (ist es nicht immer richtig, o_O)

Ich weiß, dass meine Antwort im Wesentlichen das wiederholt, was hier bereits gesagt wurde, aber manchmal ist es nur schwer herauszufinden, wo genau dieses Überschreiben geschieht.

Jazzkatze
quelle
1

Wir haben den gleichen Fehler erhalten - daher kann dies für einige nützlich sein.

Für uns war die Sache super einfach. Eine Änderung der Benutzeroberfläche verwirrte einen Endbenutzer und er drückte die Zurück-Taste im Browser zu einem "schlechten" Zeitpunkt nach dem Absenden eines Formulars (sicher, wir hätten wahrscheinlich ein PRG-Muster verwenden sollen, aber wir haben es nicht getan).

Wir haben das Problem behoben und der Benutzer drückt nicht mehr die Zurück-Taste. Problem gelöst.

Niico
quelle
0

Wenn jemand immer noch dieses Problem hat. Versuchen Sie es zu verwenden, anstatt es zu überschreiben

 public void OnActionExecuting(ActionExecutingContext context)
    {
        try
        {

            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                if (!HttpContext.Current.Response.IsRequestBeingRedirected)
                {

                    context.Result = new RedirectToRouteResult(
                new RouteValueDictionary {  { "controller", "Login" }, { "action", "Index" } });
                }
            }

        }
        catch (Exception ex)
        {
               new RouteValueDictionary { { "controller", "Login" }, { "action", "Index" } });
        }

    }
Emre
quelle
OnActionExecuting in Controller? Filter?
Kiquenet
@ Kiquenet in Filter
Emre