web-dev-qa-db-fra.com

Le serveur ne peut pas définir l'état après l'envoi des en-têtes HTTP IIS7.5

Parfois, je reçois une exception dans mon environnement de production:

  • Traitement de l'information
    • ID de processus: 3832 
    • Nom du processus: w3wp.exe 
    • Nom du compte: NT AUTHORITY\NETWORK SERVICE 
  • Informations sur les exceptions
    • Type d'exception: System.Web.HttpException 
    • Message d'exception: Le serveur ne peut pas définir l'état après l'envoi des en-têtes HTTP. 
  • Informations requises
    • URL de la demande: http://www.myulr.pl/logon
    • Chemin de la demande:/logon 
    • Adresse de l'hôte utilisateur: 10.11.9.1 
    • Utilisateur: user001 
    • Est authentifié: True 
    • Type d'authentification: Formulaires 
    • Nom du compte de fil: NT AUTHORITY\NETWORK SERVICE 
  • Informations sur le fil
    • ID de fil: 10 
    • Nom du compte de fil: NT AUTHORITY\NETWORK SERVICE 
    • Se fait passer pour: Faux 
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) 

Je n'ai pas remarqué cette erreur sur mon environnement de test. Que dois-je vérifier?

J'utilise ASP.NET MVC 2 (Release Candidate 2) 

67
marcinn

Je suis largement d'accord avec Vagrant sur la cause:

  1. votre action était en cours d'exécution, en écrivant le balisage dans le flux de réponse
  2. le flux n'était pas mis en tampon, forçant les en-têtes de réponse à être écrits avant que l'écriture du balisage puisse commencer.
  3. Votre vue a rencontré une erreur d'exécution
  4. Le gestionnaire d'exceptions commence à essayer de définir le code d'état sur quelque chose d'autre que 200
  5. Echoue car les en-têtes ont déjà été envoyés. 

Si je ne suis pas d’accord avec Vagrant, c’est le remède "ne créez aucune erreur de liaison" - vous pouvez toujours rencontrer des erreurs d’exécution dans View binding, par exemple exceptions de référence nulles.

Une meilleure solution consiste à s'assurer que Response.BufferOutput = true; avant tout octet est envoyé au flux de réponse. par exemple. dans votre action de contrôleur ou On_Begin_Request dans l'application. Cela permet de définir les transferts de serveur, les cookies/en-têtes, etc. jusqu'à la réponse se terminant naturellement, ou l'appelant la fin/le vidage. 

Bien sûr, vérifiez également que la mémoire tampon n'est pas vidée/définie sur false plus loin dans la pile.

Référence MSDN: HttpResponse.BufferOutput

58
stephbu

Juste pour ajouter aux réponses ci-dessus. J'ai eu le même problème quand j'ai commencé à utiliser ASP.Net MVC et que je faisais Response.Redirect lors d'une action du contrôleur:

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

Au lieu de renvoyer une action Response.Redirect, j'aurais dû renvoyer une RedirectAction:

return Redirect("/blah");
45
Doug

Le serveur HTTP n'envoie pas l'en-tête de réponse au client jusqu'à ce que vous spécifiiez une erreur ou que vous commenciez à envoyer des données. Si vous commencez à renvoyer des données au client, le serveur doit d'abord envoyer l'en-tête de la réponse (qui contient le code d'état). Une fois que l'en-tête a été envoyé, vous ne pouvez évidemment plus insérer de code d'état dans l'en-tête.

Voici le problème habituel. Vous démarrez la page et envoyez des balises initiales (c'est-à-dire <head>). Le serveur envoie ensuite ces balises au client, après avoir d'abord envoyé l'en-tête de réponse HTTP avec un statut supposé SUCCESS. Maintenant, vous commencez à travailler sur la viande de la page et découvrez un problème. Vous ne pouvez pas envoyer d'erreur à ce stade car l'en-tête de la réponse, qui contiendrait le statut de l'erreur, a déjà été envoyé.

La solution est la suivante: Avant de générer du contenu, vérifiez s'il y a des erreurs. Alors seulement, quand vous aurez la certitude qu'il n'y aura pas de problèmes, vous pourrez alors envoyer du contenu, comme le tag.

Dans votre cas, il semble que vous ayez une page de connexion qui traite une demande POST à partir d'un formulaire. Vous jetez probablement du code HTML initial, puis vérifiez si le nom d'utilisateur et le mot de passe sont valides. Au lieu de cela, vous devez d'abord authentifier l'utilisateur/mot de passe avant de générer any HTML.

15
Vagrant

J'ai eu le même problème avec la définition de StatusCode et ensuite Response.End dans la méthode HandleUnauthorizedRequest de AuthorizeAttribute

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

Si vous utilisez .NET 4.5+, ajoutez cette ligne avant Response.StatusCode

filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

Si vous utilisez .NET 4.0, essayez SuppressFormsAuthenticationRedirectModule .

11
VahidN

Pourquoi ne pas vérifier ceci avant de faire la redirection:

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

Vous essayez en réalité de rediriger une page qui a une réponse à jeter. Donc, tout d’abord, vous conservez les informations que vous avez jetées dans un tampon en utilisant response.buffer = true au début de la page, puis vous le videz si nécessaire en utilisant response.flush.

3
hema

Je me souviens de la partie de cette exception: "Impossible de modifier les informations d'en-tête - les en-têtes déjà envoyés par" apparaissant en PHP. Il s’est produit lorsque les en-têtes ont déjà été envoyés dans la phase de redirection et que toute autre sortie a été générée, par exemple:

echo "hello"; header ("Location: http://stackoverflow.com ");

Excusez-moi et corrigez-moi si je me trompe, mais j'apprends toujours MS Technologies et j'essayais d'aider.

1
Adil Mehmood

Je m'excuse, mais j'ajoute mes 2 centimes au fil juste au cas où quelqu'un aurait le même problème.

  • J'ai utilisé l'authentification par formulaire dans mon application MVC
  • Mais certaines actions du contrôleur étaient "anonymes", c'est-à-dire autorisées pour les utilisateurs non authentifiés.
  • Parfois, lors de ces actions, je voudrais {toujours _ que les utilisateurs soient redirigés vers le formulaire de connexion sous certaines conditions
  • faire cela - j'ai ceci dans ma méthode d'action: return new HttpStatusCodeResult(401) - et ASP.NET est super sympa de le détecter, et cela redirige l'utilisateur vers la page de connexion! Magie, c'est ça? Il a même le paramètre ReturnUrl approprié, etc.

Mais vous voyez où je vais ici? I retour 401 . Et ASP.NET redirige l'utilisateur. Ce qui est essentiellement retourne 302. Un code d'état est remplacé par un autre.

Et certains IIS serveurs (quelques-uns seulement) lèvent cette exception. Certains non. - Je ne l'ai pas sur mon test serevr, seulement sur mon serveur de production (n'est-ce pas toujours le cas juste o_O)

Je sais que ma réponse consiste essentiellement à répéter ce qui a déjà été dit ici, mais il est parfois difficile de savoir exactement où se produit cet écrasement.

1
jazzcat

Nous obtenions la même erreur - cela peut donc être utile à certains.

Pour nous la cause était super simple. Un changement d'interface a dérouté l'utilisateur final qui appuyait sur le bouton Précédent du navigateur à un «mauvais moment» après la soumission d'un formulaire (nous aurions probablement dû utiliser un modèle PRG, mais ce n'est pas le cas).

Nous avons résolu le problème et l’utilisateur n’appuie plus sur le bouton Précédent. Problème résolu.

0
niico

Si quelqu'un a toujours ce problème.Essayez d'utiliser au lieu de trop faire

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

    }
0
Emre