题 如何在ASP.NET应用程序中发送HTTP标头时如何判断?


长话短说,我有一个ASP.NET应用程序,我正在尝试调试,在某些时候,在非常特殊的情况下,应用程序将抛出异​​常 Response.Redirect() 说明:

"Cannot redirect after HTTP headers have been sent."

我或多或少得到了,除了我无法弄清楚 哪里 标题已发送。

是否有一些东西要在ASP.NET应用程序中查找,表明HTTP标头已被发送?

奖金难度: ASP.NET应用程序仍在.NET 1.1中。关于升级延迟的情况是一个非常痛苦的主题。


14
2018-03-04 19:25


起源


响应缓冲(Response.Buffer  - 你想要这个)和Response Flushing(Response.Flush()  - 你不想这样做)是两个明显的候选人。 - bzlm


答案:


HttpApplication 有一个事件 PreSendRequestHeaders 只有在标题写入时才会调用它。订阅此并记录或添加断点。

除此之外, HttpResponse 有一个 内部 财产叫 HeadersWritten (_headersWritten .NET 1.1中的字段。由于它是内部的,你不能直接访问它,但你可以通过反射。如果这仅用于内部调试(即,不是生产代码),那么使用反射就可以了。

在所有页面生命周期事件之前/之后检查此方法。一旦您知道哪个事件正在写出标题,请添加更多内容 HeadersWritten 检查以找出他们写的地方。通过逐步缩小对该物业的支票,你会发现它。

新信息

HeadersWritten 物业是从.Net 4.5.2开始公开的


16
2018-03-04 19:33



这看起来真的很好......除了我忘了提到应用程序是在.NET 1.1中,这看起来是一个.NET 2.0+解决方案。 - Tom Kidd
@Schnapple,.NET 1.1真的很老了。无论何时谈论旧版本,都应该始终指定版本。在.NET 1.1中只有一个私有字段, _headersWritten,你可以通过反思阅读。 - Samuel Neff
HeadersWritten 物业是从.Net 4.5.2开始公开的 - Jakub Konecki
@JakubKonecki感谢您的补充,良好的信息。我编辑了我的答案以加入这个。 - Samuel Neff


塞缪尔的回答刚刚为我解决了这个问题(+1)。我不能在评论中粘贴代码示例,但为了帮助其他人,这里我是如何使用他建议的事件向我的IHTTPHandler添加HeadersWritten属性:

protected bool HeadersWritten { get; private set; }

void ApplicationInstance_BeginRequest(object sender, EventArgs e)
{
    HeadersWritten = false;
}

void ApplicationInstance_PreSendRequestHeaders(object sender, EventArgs e)
{
    HeadersWritten = true;
}

public void ProcessRequest(HttpContextBase context)
{
    context.ApplicationInstance.PreSendRequestHeaders += new EventHandler(ApplicationInstance_PreSendRequestHeaders);
    do_some_stuff();
}

在我的代码中,如果我把标题搞得太晚会破坏,我只需先检查HeadersWritten属性:

if (!HeadersWritten)
{
    Context.Response.StatusDescription = get_custom_description(Context.Response.StatusCode);
}

5
2018-05-11 21:51



请注意每个实例 HttpApplication 对象可能会提供多个(但始终是顺序的)请求,所以你 必须 在BeginRequest事件期间重置标志。这也适用于 HTTPHandler 那有 IsReusable 财产归还真实。看到 HttpApplication的 和 IsResuable 在MSDN中了解详情。 - Euro Micelli
谢谢你,欧元。为了清楚起见,我将此属性以及相关的代码和事件添加到继承自IHttpHandler的类中。据我所知,这个类应该是一次性使用这个请求,因此完全免受其他请求的干扰。如果这种理解不正确,请告诉我! - Joel P.
IHttpHandler接口的一个成员是一个名为的属性 IsReusable (我在原评论中拼写错误)。如果您的实施基本上 public bool IsReusable { get { return false; } }那么你很好:ASP.NET将为每个请求实例化一个对象,然后将其丢弃。如果你回来了 true,然后ASP.NET将重用您的实例用于多个请求,并且您不是线程安全的。 - Euro Micelli
您也可以将bool存储到HttpContext.Items中,该HttpContext.Items维护请求的状态。这将确保该值仅适用于特定请求而非全局请求。看到 例。 - Richard Adleta
HeadersWritten 物业是从.Net 4.5.2开始公开的 - Jakub Konecki