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


70

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

  • 处理信息
    • 进程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(候选发布2)


我也正在发生这种情况。与您的情况一样,该错误来自HandleErrorAttribute内部。
Gabe Moothart '04

1
您能解决这个问题吗?
Azho KG 2010年

3
自切换到MVC 2以来,我遇到了同样的问题。同样,在设置Cookie时,出现类似的错误-发送标头后也不会发生。我很好奇这个答案。就我而言,在http / https之间切换似乎很重要。
马特·谢尔曼

3
我发现我试图在Actionfilter(OnActionExecuting)中重定向用户-这是一个问题
marcinn 2011年

Answers:


61

对于这一原因,我将大致同意Vagrant:

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

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

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

当然,还要检查缓冲区是否未在堆栈中进一步刷新/设置为false。

MSDN参考: HttpResponse.BufferOutput


1
我遇到相同的错误,但在我来说,当我尝试调用子操作时,就会发生此错误。我尝试Response.BufferOutput = true在父操作的开始处进行设置,但这无济于事。有任何想法吗?
Samo

萨莫(Samo),在代码的较早位置,有些内容正在向响应流中写入字节,在请求处理开始时设置了缓冲mu,例如在让Action在控制器中开始之前。
stephbu 2011年

如何HttpResponse.BufferOutput在MVC Controller中使用?
Kiquenet '19

在我的Index Action Controller中,我有: [HttpPost][ValidateAntiForgeryToken]
Kiquenet,

(假设您正在谈论System.Web.Mvc.Controller)控制器带有一个响应访问器,以提供对当前HTTP请求上下文的HttpResponse对象的访问。这样,在控制器方法中以下内容将有效:this.Response.BufferOutput
stephbu

50

仅添加到上面的响应中。当我第一次开始使用ASP.Net MVC并在控制器操作期间执行Response.Redirect时,我遇到了相同的问题:

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

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

return Redirect("/blah");

1
这正是我所做的。感谢您的修复。
Bryan Legend

1
谢谢,我在过滤器中也做了同样的事情。对其进行了更改,此问题已得到修复... // URL助手来生成重定向url。UrlHelper urlHelper =新的UrlHelper(filterContext.RequestContext); filterContext.Result =新的RedirectResult(urlHelper.Action(ActionNames.Index,ControllerNames.CustomerSearch,new {Area =“”}))); //最后是base.OnActionExecuting(filterContext);
学习...

2
我有一个涉及.NET CAS Client的类似问题,这个答案使我陷入了问题。实际上,我返回的响应是“两次”,调用CasAuthentication.SingleSignOut();。然后是RedirectToAction()。显然,这没有任何意义-您如何重定向两次,对吗?但是我当时没有意识到。我将我的LogOut操作返回类型从ActionResult更改为void,摆脱了Redirect,问题得以解决。谢谢!
Pandincus 2012年

16

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

这是通常的问题。您可以启动页面,并发送一些初始标签(例如<head>)。在首先发送带有假定的SUCCESS状态的HTTP响应标头之后,服务器将这些标签发送给客户端。现在,您开始研究页面的内容并发现问题。您目前无法发送错误,因为包含错误状态的响应标头已经发送完毕。

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

在您的情况下,似乎您有一个登录页面,该页面处理来自表单的POST请求。您可能会抛出一些初始HTML,然后检查用户名和密码是否有效。相反,您应该在完全生成任何HTML之前先对用户名/密码进行身份验证。


11

我有同样的问题与设置StatusCode,然后Response.EndHandleUnauthorizedRequest方法AuthorizeAttribute

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


10

如何在进行重定向之前检查此内容:

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

3

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


1

我记得该异常的一部分:PHP中发生了“无法修改标头信息-已发送的标头”。当在重定向阶段已经发送了报头并且生成了其他任何输出时,就会发生这种情况,例如:

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

请原谅我,如果我错了,请纠正我,但我仍在学习MS Technologies,并且我一直在尝试提供帮助。


1

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

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

但是你知道我要去哪里吗?我返回401。并且ASP.NET重定向用户。本质上是返回302。一个状态码被另一状态码代替。

某些IIS服务器(仅某些!)会抛出此异常。有些没有。-我没有在测试服务中使用它,仅在生产服务器上使用它(不是总是正确的o_O)

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


1

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

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

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


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

    }

控制器中的OnActionExecuting?筛选?
Kiquenet

@Kiquenet在筛选器中
Emre
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.