抛出异常时gzip/deflate失败

jru*_*ell 5 asp.net-mvc gzip asp.net-mvc-3

我在ASP.NET MVC 3中使用gzip/deflate ActionFilterAttribute时遇到了一个有趣的问题.如果我的应用程序抛出异常,而不是获得YSOD,我会得到一整页乱码,如下所示.

I?%&/m?{J?J??t??$ @ iG#)* eVe] f @ 흼 { { ; N' ?\fdl !???Jɞ〜|"安永")= y6hZ2kjuU + _ X-: T W v <[ ~2 g 2 ? ʋ y hYՋ t _N M l { , Xn Q } *g 7 ~ ?j'u>K?{_??IW4?>?U?w?|=-fYzR-???????|??<&?o?Z()*?S!U??k?g???????j??.????b}????9X/??J?I???Q???z?i?n?-g???????Y^????H?8/??k?}]7??@?{|?g??wUd?O?????y???o-????????? ?ZHv,?d]????>o3?=?3x?7MN???????????Ow???w?.o????<?M????;???vg???A>???{Y?N???????$p>q????/?!?y??9?2??two?????????????????n?9?r?^????!??????{???ag??\1*c??!?b?? xI u f? {' P$ v&=#s l _0 ΃ w ss 廌 ⼽ r ! [KP\7M(O4ߛ>> @"|| vy5QꆦRJSK& ߛ p v< C t 1 hOI y{j ]i ˷ ˷ D'p< $ ,?'M??r{-?}??CF???????A??9??[?½?? ?! 2?? ?:??!??{?t?;??'y??M??+?M^#x^\????Q??jM?l???(?]? ??IZ??[????+4#"?:?X????m???????dv>??????iL??I |?fL?TU??ho?? ?{L??_t??5?o????h?O?UY]#?u?[???G???=???;??8???~????d?8k?w?????yw? ֺ NXA [XMO F /噩; Y〜!

如果我删除我的CompressAttribute,它按预期工作(我看到YSOD).所以我的异常处理(ElmahHandleErrorAttribute来自Elmah.Contrib.Mvc)似乎停止了剩余的过滤器,包括CompressAttribute并且响应没有缩小.

相关代码:

public sealed class CompressAttribute : ActionFilterAttribute
{
    private const string _acceptEncodingHeader = "Accept-Encoding";
    private const string _contentEncodingHeader = "Content-Encoding";

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase request = filterContext.HttpContext.Request;

        string acceptEncoding = request.Headers[_acceptEncodingHeader];

        if (String.IsNullOrEmpty(acceptEncoding))
        {
            return;
        }

        acceptEncoding = acceptEncoding.ToUpperInvariant();

        HttpResponseBase response = filterContext.HttpContext.Response;

        if (acceptEncoding.Contains("GZIP"))
        {
            response.AppendHeader(_contentEncodingHeader, "gzip");
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
        else if (acceptEncoding.Contains("DEFLATE"))
        {
            response.AppendHeader(_contentEncodingHeader, "deflate");
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

过滤注册:

GlobalFilterCollection filters = GlobalFilters.Filters;
filters.Add(new ElmahHandleErrorAttribute(), 999); // Elmah.Contrib.Mvc
filters.Add(new CompressAttribute());
Run Code Online (Sandbox Code Playgroud)

即使抛出异常,如何确保响应是可读的?

Rob*_*non 9

这是一个稍微好一点的答案,灵感来自于iaimtomisbe的回答.它允许您将所有代码保留在一个类中.

将以下覆盖添加到CompressAttribute类:

public override void OnResultExecuted(ResultExecutedContext filterContext)
{
    if (filterContext.Exception != null)
    {
        filterContext.HttpContext.Response.Filter = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我将其放在OnActionExecuted中而不在OnResultExecuted中,则此方法有效。 (2认同)

sar*_*esh 6

这是因为当您的应用程序出现错误时,ASP.Net会删除所有自定义标题,但过滤器仍然存在.您可以根据应用程序错误重置过滤器,以避免问题消失.

protected void Application_Error(object sender, EventArgs e)
{
        Response.Filter = null;
}
Run Code Online (Sandbox Code Playgroud)