如果发生exception,“Content-encoding”标头将从HttpHandler响应中消失

我有一个自定义的HttpHandler,我在其中手动启用输出压缩,如下所示:

context.Response.AppendHeader("Content-encoding", "gzip"); context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress); 

这适用于大多数请求,但遇到exception时,“内容编码”标头会从响应中消失,而压缩filter仍保留在原位。 结果是错误页面被gzip压缩,但是浏览器没有收到表示该事实的标题。 然后浏览器尝试将仍然压缩的数据显示为文本,即gobbledygook 。

完整的测试用例代码如下所示。 尝试交替禁用压缩或不抛出exception。

有人可以解释为什么“内容编码”标题消失了吗?

我想我可以简单地启用压缩作为处理程序的最后一件事,因此如果遇到exception,它永远不会到达添加压缩filter的点; 但我看到的行为让我感到害怕。 谁能确认一下?

 public class TestHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { CompressResponse(context); context.Response.Write("Hello world"); // Throw an exception for testing purposes throw new Exception("Just testing..."); } private void CompressResponse(HttpContext context) { string acceptEncoding = context.Request.Headers["Accept-Encoding"]; if (String.IsNullOrEmpty(acceptEncoding)) { return; } // gzip or wildcard if (acceptEncoding.ToLower().Contains("gzip") || acceptEncoding.Contains("*")) { context.Response.AppendHeader("Content-encoding", "gzip"); context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress); return; } // Also handles deflate (not shown here) //  } public bool IsReusable { get { return true; } } } 

编辑:我在测试用例中看到的仍然编码的响应的屏幕截图: http : //i.imgur.com/49Vcl.png

如果你有一个例外,那么服务器将刷新当前设置的标题和内容,因为它们是错误的,就像你有一个例外。

至少,很明显你要发送的200状态(因为所有不改变状态的成功响应发送200,而未处理的exception不再成功)是错误的,但其他一切都是相关的对于你将会做但却未能实现的事情,所以这一切都是错的,一切都会好起来的。

但是filter不会重置。

如果适当,可以重置错误页面中的标题,或者除非您确定所有内容都已准备好进行刷新,否则不要设置filter。 我会选择前者,没有理由为什么错误页面也无法压缩。

如果你打电话给Flush() ,你就不能发送标题,因为你已经刷新了。 标题将去哪里?

我也遇到了这个问题。 追踪是很复杂的。 我不确定这整个情况的具体细节,但我认为发生的是内存泄漏。

当你第一次这样做时:

 context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress); 

您正在为Filter分配非托管资源 。 通常情况下,这将包含在using语句中,以便在出现任何问题时妥善处理。

所以,当出现问题时,就会出现问题。 Filter包含一个仍然打开的流,即使响应是用死黄色屏幕写入的。 随之而来的是疯狂(如屏幕截图所示)。

不要害怕! 实际上有一种简单的方法可以解决这个问题。 处理filter。 幸运的是,已有一个地方可以应用此全局检查filter处理。

的global.asax.cs

 public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute());//default handler filters.Add(new HandleErrorEncodingAttribute());//extra check for filter disposal } 

error handling程序名称

 public class HandleErrorEncodingAttribute : FilterAttribute, IExceptionFilter { public virtual void OnException(ExceptionContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } if (filterContext.IsChildAction) { return; } // If custom errors are disabled, we need to let the normal ASP.NET exception handler // execute so that the user can see useful debugging information. if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) { filterContext.HttpContext.Response.Filter.Dispose();//fixes response stream return; } } } 

WebForms应用程序上强制使用gzip时,我遇到了同样的事情。 为了解决这个问题,我必须清除Global.asax.cs中Application_Error方法中的filter

 protected void Application_Error(Object sender, EventArgs e) { Response.Filter = null; } 

发生这种情况的原因是b / c在应用程序出错之前设置了filter。 由于某种原因,黄屏错误消息清除了内容编码标题,但对响应filter没有任何作用。

我测试你的代码,我找不到任何问题。 是的,没有设置gzip,但是还没有设置filter,asp获取控件并发送错误。

强制标题刷新会产生真正的问题

  CompressResponse(context); context.Response.Flush(); 

如果我强制使用gzip标头,则页面无法正确呈现。

两个人认为这可能是你的问题。 您没有设置页面编码

 context.Response.ContentEncoding = new UTF8Encoding(); 

并且您没有设置ContentType

 context.Response.ContentType = "text/plain"; 

也许其中一些原因是您没有更正页面渲染。 在我的测试中,即使你所描述的问题没有出现。