【问题标题】:MVC 3 compression filter causing garbled outputMVC 3 压缩过滤器导致输出乱码
【发布时间】:2010-12-28 18:06:29
【问题描述】:

所以,我有一个名为 CompressAttribute 的自定义属性,它在 global.asax 中设置为全局过滤器。它使用反射来检查当前操作方法的返回类型,如果是“ViewResult”,它会使用 GZip 或 Deflate 压缩输出。它工作得很好,除非页面抛出 500 服务器错误。如果遇到错误,而不是显示 .NET 错误页面,我会得到一堆这样的:

��������`I�%&/m�{J�J��t��

显然它正在尝试对导致问题的 500 服务器错误页面进行编码。处理这个问题的最佳方法是什么?

这是过滤器代码:

public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            MethodInfo actionMethodInfo = Common.GetActionMethodInfo(filterContext);
            if (GetReturnType(actionMethodInfo).ToLower() != "viewresult") return;

            HttpRequestBase request = filterContext.HttpContext.Request;

            string acceptEncoding = request.Headers["Accept-Encoding"];

            if (string.IsNullOrEmpty(acceptEncoding)) return;

            acceptEncoding = acceptEncoding.ToUpperInvariant();

            HttpResponseBase response = filterContext.HttpContext.Response;

            if (acceptEncoding.Contains("GZIP"))
            {
                response.AppendHeader("Content-encoding", "gzip");
                response.Filter = new WebCompressionStream(response.Filter, CompressionType.GZip);
            }
            else if (acceptEncoding.Contains("DEFLATE"))
            {
                response.AppendHeader("Content-encoding", "deflate");
                response.Filter = new WebCompressionStream(response.Filter, CompressionType.Deflate);
            }
        }

【问题讨论】:

    标签: c# asp.net-mvc action-filter


    【解决方案1】:

    好的,我可以通过清除 Application_Error 事件中的 Response.Filter 属性来解决这个问题:

    public void Application_Error(object sender, EventArgs e)
    {
        Response.Filter.Dispose();
    }
    

    想知道是否有更正确的方法来做到这一点......

    【讨论】:

    • 这并不能真正解决问题。我需要能够在调试过程中看到异常信息、堆栈跟踪信息等。
    • 这并不意味着您不能使用HandleError 属性来做到这一点。
    • 谢谢!一段时间以来,我们在 IIS 7 和 7.5 中遇到了这个错误,想知道为什么。它不会发生在 IIS 6 或 Cassino 上。您的解决方案解决了这个问题。
    • 优秀的解决方案。 Dispose() 似乎比将 Response.Filter 设置为 null 更“正确”。还消除了以后每次进入调试模式的时间。
    【解决方案2】:

    您也可以通过附加到OnResultExecuting 而不是OnActionExecuting 来解决此问题。这有几个优点

    1. 您无需借助反思即可发现操作结果。
    2. OnResultExecuting 在特殊情况下不会执行(MVC 将调用 OnException 但不会调用 OnResultExecuting

    类似这样的:

    public sealed class MyAttribute  : ActionFilterAttribute
    {
        /// <summary>
        /// Called by MVC just before the result (typically a view) is executing.
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            var result = filterContext.Result;
            if (result is ViewResultBase)
            {
                var response = filterContext.HttpContext.Response;
    
                // Check your request parameters and attach filter.
            }
        }
    

    【讨论】:

      【解决方案3】:

      如果已将任何内容写入输出,则接受的答案将不起作用。

      您可以确保标题被保留在适当的位置,而不是处理过滤器:

       protected void Application_PreSendRequestHeaders()
      {
          // ensure that if GZip/Deflate Encoding is applied that headers are set
          // also works when error occurs if filters are still active
          HttpResponse response = HttpContext.Current.Response;
          if (response.Filter is GZipStream && response.Headers["Content-encoding"] != "gzip")
              response.AppendHeader("Content-encoding", "gzip");
          else if (response.Filter is DeflateStream && response.Headers["Content-encoding"] != "deflate")
              response.AppendHeader("Content-encoding", "deflate");
      }
      

      【讨论】:

      • 这对我有用。错误时正在清除标头,这可以确保发送正确的内容标头。
      【解决方案4】:

      我在 asp.net mvc 1.0 浏览一个包含 RenderAction 的页面时遇到了同样的问题(来自期货程序集)。显然问题是响应被编码了两次。我必须为此子操作创建一个操作过滤器,以便在 RouteData 的 DataTokens 集合中设置一个标志。然后我必须修改压缩过滤器,以便在设置标志的情况下返回。我还必须处理过滤器的执行顺序。也许这会有所帮助,验证在引发错误页面时是否多次调用压缩过滤器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-08
        • 1970-01-01
        • 2010-12-18
        • 1970-01-01
        • 2021-07-18
        • 1970-01-01
        相关资源
        最近更新 更多