我有一个自定义的HttpHandler,我在其中手动启用输出压缩,如下所示:
context.Response.AppendHeader("Content-encoding", "gzip");
context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
这适用于大多数请求,但遇到异常时,“Content-encoding”标头会从响应中消失,而压缩过滤器仍保留在原位。结果是错误页面被gzip压缩,但浏览器没有收到表示该事实的标题。然后,浏览器尝试将仍然压缩的数据显示为文本,即gobbledygook。
完整的测试用例代码如下所示。尝试交替禁用压缩或不抛出异常。
有人可以解释“内容编码”标题消失的原因吗?
我想我可以简单地启用压缩作为处理程序执行的 last 事务,因此如果遇到异常,它永远不会到达添加压缩过滤器的点;但我看到的行为让我感到害怕。任何人都可以确认吗?
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)
// <snip>
}
public bool IsReusable
{
get { return true; }
}
}
编辑:我在测试用例中看到的仍然编码的响应的屏幕截图:http://i.imgur.com/49Vcl.png
答案 0 :(得分:1)
在 WebForms 应用程序上强制使用gzip时,我遇到了同样的事情。为了解决这个问题,我必须清除Global.asax.cs中 Application_Error 方法中的过滤器
protected void Application_Error(Object sender, EventArgs e)
{
Response.Filter = null;
}
发生这种情况的原因是b / c在应用程序出错之前设置了过滤器。由于某种原因,黄屏错误消息清除了内容编码标头,但对响应过滤器没有任何作用。
答案 1 :(得分:0)
如果您有异常,那么服务器将刷新当前设置的标题和内容,因为它们是错误的,就像您在执行完所有操作后一样。
至少,很明显你要发送的200状态(因为所有不改变状态的成功响应发送200,并且在未处理的异常时它不再成功)是错误的,但是其他一切都与你要做的事情有关但却未能实现,所以这一切都是错的,一切都会好起来。
虽然过滤器没有重置。
如果合适,可以重置错误页面中的标题,或者除非您确定所有内容都已准备好进行刷新,否则不要设置过滤器。我会选择前者,没有理由不能压缩错误页面。
如果您拨打Flush()
,则无法发送标头,因为您已经刷新了。标题将去哪里?
答案 2 :(得分:0)
我也遇到了这个问题。追踪是很复杂的。我不确定这整个情况的具体细节,但我认为发生的是内存泄漏。
当你第一次这样做时:
context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
您正在为Filter
分配非托管资源。通常情况下,这将包含在using
语句中,以便在出现任何错误的情况下正确处理 。
所以,当出现问题时,就会出现问题。 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
}
错误处理程序名称空间
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;
}
}
}
答案 3 :(得分:-1)
我测试你的代码,我找不到任何问题。是的,没有设置gzip,但是过滤器也没有设置,asp得到控件并发送错误。
强制标题刷新会产生真正的问题
CompressResponse(context);
context.Response.Flush();
如果我强制使用gzip标头,则页面无法正确呈现。
两个人认为这可能是你的问题。您没有设置页面编码
context.Response.ContentEncoding = new UTF8Encoding();
并且您没有设置ContentType
context.Response.ContentType = "text/plain";
也许其中一些原因是您没有更正页面渲染。在我的测试中,即便如此,你所描述的问题也没有出现。