2012-02-14 96 views
4

我在ASP.NET MVC 3中有一個有趣的問題,即gzip/deflate ActionFilterAttribute。如果我的應用程序引發異常,而不是獲取YSOD,如下所示的亂碼。當拋出異常時gzip/deflate失敗

I�%&/m�{J�J��t�� $ @ iG#) * eVe] f @ 흼 { { ; N' ?\fdlJɞ〜|!?「安永」)= 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 ( 4 ߛ> > @「| |v y5 QꆦR JSK & ߛ 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� ֺ Nx A [XMO F /噩; Y〜

如果我刪除我的CompressAttribute,它按預期工作(我看到了YSOD)!因此,我的異常處理(來自Elmah.Contrib.Mvc的ElmahHandleErrorAttribute)似乎會暫停其餘的過濾器,包括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); 
     } 
    } 
} 

註冊過濾器:

GlobalFilterCollection filters = GlobalFilters.Filters; 
filters.Add(new ElmahHandleErrorAttribute(), 999); // Elmah.Contrib.Mvc 
filters.Add(new CompressAttribute()); 

我怎樣才能確保響應是可讀的,即使拋出異常?

+0

我也打開其他/更好的方法來啓用http壓縮。 – jrummell 2012-02-14 19:04:56

+0

你看過IIS內置的動態壓縮嗎? – 2012-02-14 19:37:06

+0

@amit_g我沒有。你有鏈接嗎? – jrummell 2012-02-14 19:49:46

回答

6

這是因爲當您的應用程序出現錯誤時,ASP.Net將刪除您的所有自定義標題,但篩選器仍然存在。您可以重置應用程序錯誤上的過濾器,以防止問題消失。

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

工作,謝謝! – jrummell 2012-02-14 20:34:53

+0

@ jrummell真棒,你能接受答案,如果這是你在找什麼。 – sarvesh 2012-02-15 14:58:43

8

這是一個稍微好一點的答案,靈感來自iaimtomisbehave的答案。它可以讓你將所有的代碼保存在一個類中。

添加以下重寫你的CompressAttribute類:

public override void OnResultExecuted(ResultExecutedContext filterContext) 
{ 
    if (filterContext.Exception != null) 
    { 
     filterContext.HttpContext.Response.Filter = null; 
    } 
} 
+0

這實際上是我最終做的。 – jrummell 2012-02-20 13:24:35

+1

這工作,如果我把它放在OnActionExecuted,但不是在OnResultExecuted。 – andrewpm 2015-11-10 14:03:22

0

Google搜索互聯網一樣問題的解決方案,並在這裏結束了。相當有用的答案啓發我實現我自己的版本如下:

static public void EnableGzip() 
{ 
    var c = HttpContext.Current; 
    string a = c.Request.Headers["Accept-Encoding"]; 
    if (String.IsNullOrEmpty(a)) 
     return; 
    if (!a.Contains("gzip")) 
     return; 
    c.Response.Filter = new GZipStream(
     c.Response.Filter, CompressionMode.Compress); 
    c.Response.AppendHeader("Content-Encoding", "gzip"); 
    EventHandler errorHandler = null; 
    errorHandler = delegate 
    { 
     c.Response.Filter = null; 
     c.ApplicationInstance.Error -= errorHandler; 
    }; 
    c.ApplicationInstance.Error += errorHandler; 
} 

請隨時批評這一點。