【问题标题】:Server cannot set status after HTTP headers have been sent IIS7.5IIS7.5 发送 HTTP 标头后服务器无法设置状态
【发布时间】:2011-01-23 21:36:10
【问题描述】:

有时我在生产环境中遇到异常:

  • 流程信息
    • 进程 ID:3832
    • 进程名称:w3wp.exe
    • 账户名称:NT AUTHORITY\NETWORK SERVICE
  • 异常信息
    • 异常类型:System.Web.HttpException
    • 异常消息:发送 HTTP 标头后服务器无法设置状态。
  • 索取信息
    • 请求网址:http://www.myulr.pl/logon
    • 请求路径:/logon
    • 用户主机地址:10.11.9.1
    • 用户:user001
    • 已通过身份验证:真
    • 身份验证类型:表单
    • 线程账户名:NT AUTHORITY\NETWORK SERVICE
  • 话题信息
    • 线程 ID:10
    • 线程账户名:NT AUTHORITY\NETWORK SERVICE
    • 正在冒充:假
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) 

我在我的测试环境中没有注意到这个错误我应该检查什么?

我正在使用 ASP.NET MVC 2(Release Candidate 2)

【问题讨论】:

  • 这也发生在我身上。与您的情况一样,错误来自 HandleErrorAttribute 内部。
  • 你能解决这个问题吗?
  • 自从切换到 MVC 2 后,我也遇到了同样的问题。此外,在设置 cookie 时,类似的错误 - 在发送标头后不会发生。我很好奇答案。就我而言,在 http/https 之间切换似乎起了作用。
  • 我发现我试图在 Actionfilter (OnActionExecuting) 中重定向用户 - 这是一个问题

标签: asp.net-mvc http iis-7


【解决方案1】:

在您指定错误或开始发送数据之前,HTTP 服务器不会将响应标头发送回客户端。如果您开始将数据发送回客户端,则服务器必须首先发送响应头(包含状态代码)。发送标头后,您显然不能再在标头中放置状态代码。

这是常见的问题。您启动页面,并发送一些初始标签(即&lt;head&gt;)。在首先发送带有假定成功状态的 HTTP 响应标头之后,服务器然后将这些标签发送到客户端。现在您开始处理页面的内容并发现问题。此时您不能发送错误,因为包含错误状态的响应标头已经发送。

解决方案是这样的: 在生成任何内容之前,请检查是否会出现任何错误。只有这样,当你确定没有问题时,你才能开始发送内容,比如标签。

在您的情况下,您似乎有一个登录页面来处理来自表单的 POST 请求。您可能会丢弃一些初始 HTML,然后检查用户名和密码是否有效。相反,您应该首先验证用户/密码,然后再生成 任何 HTML。

【讨论】:

    【解决方案2】:

    我记得这个异常中的一部分:“无法修改标头信息 - 标头已由 PHP 发送”。它发生在标头已经在重定向阶段发送并生成任何其他输出时,例如:

    回声“你好”; header("位置:http://stackoverflow.com");

    如果我错了,请原谅我并纠正我,但我仍在学习 MS 技术,我正在努力提供帮助。

    【讨论】:

      【解决方案3】:

      我大致同意 Vagrant 的原因:

      1. 您的操作正在执行,正在将标记写入响应流
      2. 流未缓冲,强制在标记写入开始之前写入响应标头。
      3. 您的视图遇到运行时错误
      4. 异常处理程序开始尝试将状态代码设置为非 200 的其他值
      5. 失败,因为标头已经发送。

      我不同意 Vagrant 的地方是“在绑定中不出错”补救措施 - 您仍然可能在视图绑定中遇到运行时错误,例如空引用异常。

      对此更好的解决方案是确保Response.BufferOutput = true; 在任何字节被发送到响应流之前。例如在您的控制器操作或应用程序中的 On_Begin_Request 中。这使得服务器传输、cookies/headers 设置等正确,直到自然结束响应,或调用 end/flush。

      当然还要检查堆栈中的缓冲区是否没有被刷新/设置为 false。

      MSDN 参考: HttpResponse.BufferOutput

      【讨论】:

      • 我遇到了同样的错误,但在我的情况下,当我尝试调用子操作时会发生这种情况。我尝试在父操作开始时设置Response.BufferOutput = true,但这没有帮助。有什么想法吗?
      • Samo,在你的代码前面的某个地方,有些东西正在向响应流写入字节,在请求处理开始时设置缓冲 mu,例如在你让你的动作在你的控制器中开始之前。
      • 如何在MVC控制器中使用HttpResponse.BufferOutput
      • 在我的索引操作控制器中,我有:[HttpPost][ValidateAntiForgeryToken]
      • (假设您在谈论 System.Web.Mvc.Controller)控制器带有一个 Response 访问器,以提供对当前 HTTP 请求上下文的 HttpResponse 对象的访问权限。这样在控制器方法中以下是有效的:this.Response.BufferOutput
      【解决方案4】:

      只是为了添加到上面的回复中。当我第一次开始使用 ASP.Net MVC 并且在控制器操作期间执行 Response.Redirect 时,我遇到了同样的问题:

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

      我应该返回 RedirectAction,而不是返回 Response.Redirect 操作:

      return Redirect("/blah");
      

      【讨论】:

      • 谢谢,我在过滤器中也是这样做的。改变了它,这得到了修复... //Url helper 生成重定向 url。 UrlHelper urlHelper = new UrlHelper(filterContext.RequestContext); filterContext.Result = new RedirectResult(urlHelper.Action(ActionNames.Index, ControllerNames.CustomerSearch, new{Area = ""})); //最后 base.OnActionExecuting(filterContext);
      • 我遇到了一个涉及 .NET CAS 客户端的类似问题,这个答案将我引向了我的问题。我实际上是在“两次”返回响应,调用 CasAuthentication.SingleSignOut();后跟一个 RedirectToAction()。显然这没有意义——你怎么能重定向两次,对吧?但当时我并没有意识到。我将 LogOut 操作返回类型从 ActionResult 更改为 void,摆脱了 Redirect,问题就解决了。谢谢!
      【解决方案5】:

      您实际上是在尝试重定向一个页面,该页面有一些响应抛出。因此,首先您将使用response.buffer = true 放入页面开头的缓冲区中保存的信息,然后在需要时使用response.flush 刷新它,此错误将得到修复

      【讨论】:

        【解决方案6】:

        在进行重定向之前检查一下如何:

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

        【讨论】:

          【解决方案7】:

          AuthorizeAttributeHandleUnauthorizedRequest 方法中设置StatusCodeResponse.End 时遇到了同样的问题

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

          如果您使用的是 .NET 4.5+,请在 Response.StatusCode 之前添加此行

          filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
          

          如果您使用的是 .NET 4.0,请尝试SuppressFormsAuthenticationRedirectModule

          【讨论】:

          • 另请注意,Response.End(); 本身也是有问题的,因为它隐含地导致发送 HTTP 200 状态代码。一般来说,不应该手动处理Response 对象,而是抛出/返回一个适当的异常/响应对象,让 ASP.NET 做它的事情。
          【解决方案8】:

          我很抱歉,但我将我的 2 美分添加到线程中,以防万一有人遇到同样的问题。

          • 我在 MVC 应用程序中使用了表单身份验证
          • 但某些控制器操作是“匿名的”,即允许未经身份验证的用户使用
          • 有时在这些操作中,我仍然希望用户在某些情况下被重定向到登录表单
          • 要做到这一点 - 我的操作方法中有这个:return new HttpStatusCodeResult(401) - ASP.NET 非常好地检测到这一点,它会将用户重定向到登录页面!魔术,对吧?它甚至有正确的ReturnUrl 参数等。

          但是你明白我要到哪里了吗?我返回 401。并且 ASP.NET 重定向用户。这本质上是返回 302。一个状态码被另一个替换。

          还有一些 IIS 服务器(只是一些!)抛出这个异常。有些没有。 - 我的测试服务器上没有它,只有在我的生产服务器上(不是总是这样o_O)

          我知道我的回答基本上是在重复这里已经说过的话,但有时很难弄清楚这种覆盖究竟发生在哪里。

          【讨论】:

            【解决方案9】:

            如果有人仍然有这个问题。尝试使用而不是覆盖

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

            【讨论】:

            • OnActionExecuting 在控制器中?过滤器?
            • 过滤器中的@Kiquenet
            【解决方案10】:

            我们遇到了同样的错误 - 所以这可能对某些人有用。

            对我们来说,原因非常简单。界面更改使最终用户感到困惑,他们在提交表单后的“糟糕”时间按下了浏览器中的后退按钮(当然我们可能应该使用 PRG 模式,但我们没有)。

            我们解决了这个问题,用户不再按返回按钮。问题解决了。

            【讨论】:

              猜你喜欢
              • 2014-01-27
              • 2015-11-07
              • 1970-01-01
              • 2019-07-22
              • 2016-08-27
              • 2015-06-24
              • 2015-05-16
              • 1970-01-01
              • 2012-09-28
              相关资源
              最近更新 更多