我在ASP.NET MVC 3中使用gzip / deflate ActionFilterAttribute时遇到了一个有趣的问题。如果我的应用程序抛出异常,而不是获得YSOD,我会得到一整页乱码,如下所示。
I�%&/m�{J�J��t��
$ @ IG#)* EVE F的@흼{{; N” ?\fdlJɞ〜|!?“安永”)= y6hZ2kjuU ?+ _ X-: TWV&LT; [〜2G2ʋyhYՋ吨 _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ي
?xIuf ?{'P $ V&安培;!=#sl_0wss廌⼽[R [KP \ 7M(O4ߛ&GT;&GT; @“|| vy5QꆦRJSK&安培;ߛ PV&LT; Ct1hOIy {j]的我 D'P&LT; $,�'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)。因此,似乎我的异常处理(来自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 :(得分:8)
这是一个稍微好一点的答案,灵感来自于iaimtomisbe的回答。它允许您将所有代码保留在一个类中。
将以下覆盖添加到CompressAttribute类:
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
filterContext.HttpContext.Response.Filter = null;
}
}
答案 1 :(得分:6)
这是因为当您的应用程序出现错误时,ASP.Net将删除所有自定义标题,但过滤器仍然存在。您可以根据应用程序错误重置过滤器,以避免问题消失。
protected void Application_Error(object sender, EventArgs e)
{
Response.Filter = null;
}
答案 2 :(得分:0)
用互联网搜索相同问题的解决方案并最终到达此处。相当有用的答案激励我实现我自己的下面提到的版本:
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;
}
请随意批评这一点。