【问题标题】:ASP.Net - Using gzip results in corruption when retrieved from cacheASP.Net - 从缓存中检索时使用 gzip 会导致损坏
【发布时间】:2012-01-08 04:46:59
【问题描述】:

使用 ASP.Net 2.0 和 IIS 6

我通过扩展 IHttpModule 并在 Web.config 文件中注册来启用压缩

public class EnableCompression : IHttpModule
{

    public void Init(HttpApplication application)
    {
        application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
    }

    private void Application_BeginRequest(Object source, EventArgs e)
    {
        HttpContext context = HttpContext.Current;
        String encoding = context.Request.Headers.Get("Accept-Encoding");

        if (encoding == null)
            return;

        encoding.ToLower();

        if (encoding.Contains("gzip"))
        {
            context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
            HttpContext.Current.Response.AppendHeader("Content-Encoding", "gzip");
        }
        else
        {
            context.Response.Filter = new DeflateStream(context.Response.Filter, CompressionMode.Compress);
            HttpContext.Current.Response.AppendHeader("Content-Encoding", "deflate");
        }
    }

    void IHttpModule.Dispose()
    {
        throw new Exception("The Method or Operation is not Implemented");
    }

}

在我还在我的母版页代码文件的页面加载事件中设置过期标头之前,上述工作正常

protected void Page_Load(object sender, EventArgs e)
{
    Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
    Response.Cache.SetExpires(DateTime.Now.AddMinutes(10));
    Response.Cache.SetValidUntilExpires(true);
    Response.Cache.SetLastModified(DateTime.Now);
} 

设置过期标头后,一旦浏览器从缓存中检索数据,我就会得到一堆垃圾。所以第一次加载页面时,没问题。如果我转到一个新页面然后又回到第一页,我只会得到一个完整的页面:

��`I�%&/m�{J�J��t��`$ؐ@�����iG#)�*�

如果我禁用压缩但保留 expires 标头,那很好 如果我禁用 expires 标头但启用压缩,那很好 如果我同时启用两者,我会得到一个充满垃圾的页面。

我不知道发生了什么。

Response Header
HTTP/1.1 200 OK
Date: Sun, 08 Jan 2012 07:23:15 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Content-Encoding: gzip
Cache-Control: private
Expires: Sun, 08 Jan 2012 07:33:00 GMT
Last-Modified: Sun, 08 Jan 2012 07:23:00 GMT
Vary: *
Content-Type: text/html; charset=utf-8
Content-Length: 13613

Request Header
GET /eng/DE/ HTTP/1.1
Host: wwwnpg
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Cookie: ASP.NET_SessionId=gxdxwnnum5rumue13rxmc5mb

【问题讨论】:

标签: asp.net


【解决方案1】:

您应该使用像 Fiddler 这样的网络代理检查您的 HTTP 标头,但我怀疑发生的事情是运行时正在缓存您预先过滤的内容,以及您设置的标头。所以浏览器最终会认为内容已被压缩,而实际上并非如此。

解决方案是在页面生命周期的后期设置压缩Filter,例如在HttpModulePostRequestHandlerExecute 事件中。我使用该事件来设置一个空格Filter,它对我来说与输出缓存(使用 IIS7+)配合得很好。

在生命周期后期设置过滤器的另一个原因是处理 HTTP 错误页面。否则,如果您的页面抛出 Exception,则可能会设置 Filter,但运行时将丢弃任何自定义标头。

您还应该根据Accept-Encoding 标头更改输出缓存,方法是在OutputCache 指令中设置VaryByHeader

<%@ OutputCache Duration="60" VaryByParam="None"
    VaryByHeader="Accept-Encoding" %>

【讨论】:

  • 我不知道为什么,但我没有先尝试您的解决方案,而是花了很多时间尝试在您提供的 west-wind 链接中实施 PreSendRequestHeaders 检查解决方案(在 HttpContext 上保持 Null 异常.Current.Response)。几乎是凌晨 2 点,我终于尝试在 PostRequestHandlerExecute 事件中设置过滤器......它立即工作。谢谢你。谢谢。
  • 我突然想到,链接可能会导致更多的混乱而不是帮助...对此感到抱歉,但很高兴听到它对您有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-09
相关资源
最近更新 更多