6

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

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

这适用于大多数请求,但是当遇到异常时,“Content-encoding”标头会从响应中消失,而压缩过滤器仍然存在。结果是错误页面被 gzip 压缩,但浏览器没有收到表明这一事实的标题。然后浏览器尝试将仍然压缩的数据显示为文本,即gobbledygook

完整的测试用例代码如下所示。尝试交替禁用压缩或不引发异常。

谁能解释为什么“内容编码”标题消失了?

我想我可以简单地启用压缩作为处理程序所做的最后一件事,这样如果遇到异常,它就永远不会到达添加压缩过滤器的位置;但我看到的行为让我觉得是个错误。任何人都可以确认吗?

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

4

4 回答 4

1

在WebForms应用程序上强制 gzip 时,我也发生了同样的事情。为了修复它,我必须清除Global.asax.cs中Application_Error方法中的过滤器

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

发生这种情况的原因是在应用程序出现错误之前设置了过滤器。由于某种原因,黄屏错误消息清除了 Content-encoding 标头,但对响应过滤器没有任何作用。

于 2014-05-05T17:38:52.010 回答
0

If you have an exception, then the server will flush the currently set headers and content, because they're wrong, as you did after all have an exeption.

At the very least, it's clear that the 200 status you were going to send (because all successful responses that don't change the status send a 200, and upon an unhandled exception it was no longer succesful) is wrong, but everything else related to something you were going to do but failed to achieve, so it's all wrong and it all goes.

Filters aren't reset though.

Either reset the headers in the error page if appropriate, or don't set the filter unless you can be sure that everything is ready to flush. I'd go for the former, no reason why error pages can't be compressed too.

You can't send a header if you've called Flush(), because well, because you've flushed. Where's the header going to go?

于 2012-01-13T02:14:19.010 回答
0

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

当你第一次这样做时:

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

您正在将非托管资源分配给Filter. 通常这将被包装在一个using语句中,以便在出现任何问题时得到适当的处理。

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

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

全局.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;
        }
    }
}
于 2013-11-27T21:13:06.993 回答
-1

我测试了您的代码,但找不到任何问题。是的,gzip 没有设置,但过滤器也没有设置,asp 得到控制并发送错误。

强制标头刷新是一个真正的问题

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

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

两个认为这里也许是你的问题。您没有设置页面编码

context.Response.ContentEncoding = new UTF8Encoding();

并且您没有设置 ContentType

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

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

于 2012-01-13T00:03:20.950 回答