IIS7发送HTTP标头后,服务器无法设置状态

时间:2010-03-04 22:21:54

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

有时我的生产环境会出现异常:

  
      
  • 流程信息      
        
    • 进程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
    •   
    • 冒充:False
    •   
  •   
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)

9 个答案:

答案 0 :(得分:59)

我会广泛同意Vagrant的原因:

  1. 您的操作正在执行,将标记写入响应流
  2. 该流是无缓冲的,强制在标记写入开始之前写入响应头。
  3. 您的视图遇到运行时错误
  4. 异常处理程序尝试将状态代码设置为非200
  5. 失败,因为标题已经发送。
  6. 我不同意Vagrant的原因是“导致绑定中没有错误”的补救措施 - 您仍然可能在View绑定中遇到运行时错误,例如空引用异常。

    更好的解决方案是确保在将任何字节发送到Response流之前Response.BufferOutput = true;。例如在您的控制器操作或应用程序中的On_Begin_Request。这样就可以设置服务器传输,cookie /头等,直到自然结束响应,或者调用结束/刷新。

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

    MSDN参考: HttpResponse.BufferOutput

答案 1 :(得分:45)

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

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

我应该返回Response.Redirect

,而不是返回RedirectAction动作
return Redirect("/blah");

答案 2 :(得分:15)

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

这是通常的问题。您启动页面,并发送一些初始标签(即<head>)。在首先发送具有假定的SUCCESS状态的HTTP响应头之后,服务器然后将这些标签发送到客户端。现在,您开始研究页面的内容并发现问题。此时您无法发送错误,因为已经发送了包含错误状态的响应标头。

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

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

答案 3 :(得分:11)

我在StatusCode的{​​{1}}方法中设置Response.End然后HandleUnauthorizedRequest时遇到了同样的问题

AuthorizeAttribute

如果您使用的是.NET 4.5+,请在var ctx = filterContext.HttpContext; ctx.Response.StatusCode = (int)HttpStatusCode.Forbidden; ctx.Response.End();

之前添加此行
Response.StatusCode

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

答案 4 :(得分:3)

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

答案 5 :(得分:1)

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

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

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

答案 6 :(得分:1)

我很抱歉,但是如果有人遇到同样的问题,我会在线程中添加2美分。

  • 我在MVC应用中使用了表单身份验证
  • 但是有些控制器动作是匿名的&#34;即允许未经过身份验证的用户
  • 有时在这些操作中,我仍然希望用户在某种情况下被重定向到登录表单
  • 要做到这一点 - 我在我的动作方法中有这个:return new HttpStatusCodeResult(401) - 并且ASP.NET非常高兴检测到这一点,它将用户重定向到登录页面!魔术吧?它甚至具有适当的ReturnUrl参数等。

但你知道我到哪儿了吗?我返回401 。 ASP.NET重定向用户。这本质上是返回302 。一个状态代码被另一个替换。

一些IIS服务器(只是一些!)抛出此异常。有些人不愿意。 - 我没有在我的测试服务器上,只在我的生产服务器上(因为它始终是正确的o_O)

我知道我的回答基本上是重复已经在这里说过的内容,但有时很难弄清楚这种覆盖的确切位置。

答案 7 :(得分:1)

我们遇到了相同的错误-因此这可能对某些人有用。

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

我们已解决了该问题,用户不再按下后退按钮。问题解决了。

答案 8 :(得分:0)

如果有人仍有这个问题。请尝试使用而不是ovverriding

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

    }