【问题标题】:Custom IIS module conflicting with gzip自定义 IIS 模块与 gzip 冲突
【发布时间】:2011-04-10 02:59:52
【问题描述】:

作为一个实验,我一直在玩弄创建一个 IIS 托管模块来动态修改 CSS 文件的想法。背景故事是所有 Web 应用程序都保留一个共享且通用的版本号,我们将其附加到每个 JS、CSS 和图像引用(在 HTML 中),我想修改 CSS 的实际内容以也将版本号附加到图像引用在 CSS 中。所以,例如:

span.warning { background-image: url(warning-icon.png) }

应该变成:

span.warning { background-image: url(warning-icon.png?123) }

现在,我知道有很多不同的方法可以解决这个问题(有些可能更好),但我想知道是否有人可以回答与我一直在玩的问题相关的问题。

到目前为止,我已经了解到托管 HTTP 模块不能直接修改响应流(我认为),正确的方法是附加一个可以完成工作的输出过滤器流。我编写了以下测试模块:

public class HttpCSSModule : IHttpModule
{

    public void Init(HttpApplication httpApplication)
    {
        httpApplication.BeginRequest += new EventHandler(
            (s, e) => AttachFilter((HttpApplication)s));
    }

    private void AttachFilter(HttpApplication httpApplication)
    {
        HttpRequest httpRequest = httpApplication.Context.Request;
        HttpResponse httpResponse = httpApplication.Context.Response;
        if (httpRequest.Path.EndsWith(".css", StringComparison.CurrentCultureIgnoreCase))
        {
            if (!string.IsNullOrEmpty(httpRequest.Url.Query))
            {
                httpResponse.Filter = new CSSResponseStreamFilter(
                    httpResponse.Filter, httpRequest.Url.Query);
            }
        }
    }

    public void Dispose()
    {
    }

    private class CSSResponseStreamFilter : Stream
    {

        private Stream inner;
        private string version;
        private MemoryStream responseBuffer = new MemoryStream();

        public CSSResponseStreamFilter(Stream inner, string version)
        {
            this.inner = inner;
            this.version = version;
        }

        public override void Close()
        {

            if (responseBuffer.Length != 0)
            {

                string stylesheet = Encoding.ASCII.GetString(
                    responseBuffer.GetBuffer(), 0, (int)responseBuffer.Length);

                // crude, just testing
                string versionedStylesheet = stylesheet.
                    Replace(".png", ".png" + version).
                    Replace(".jpg", ".jpg" + version).
                    Replace(".gif", ".gif" + version);

                byte[] outputBytes = Encoding.ASCII.GetBytes(versionedStylesheet);
                innerStream.Write(outputBytes, 0, outputBytes.Length);

            }

            innerStream.Close();

        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            responseBuffer.Write(buffer, offset, count);
        }            

        // other Stream members

    }

}

该模块有效,但并非总是如此,而且有些事情我不明白。最大的问题是开启静态文件压缩时模块不工作。当打开静态文件压缩时,对 CSS 文件的第一个请求会像往常一样为文件提供服务,但可能 IIS 会保留 gzip 压缩版本,并且在任何后续请求中,我的自定义流都会传递 gzip 压缩流。我还没有找到检测它的方法,但可能存在更深层次的问题,因为我可能并不真正了解 IIS 模块应该如何工作。我的模块应该对另一个模块做出任何假设,或者至少应该能够定义它们在 IIS 配置中处理请求的顺序,这似乎是错误的。但是,这似乎没有意义,因为每个模块都可以注册以处理请求生命周期中的任何事件。

因此,如果我必须将我的想法重新表述为更精致的问题,那么问题将是:

如何确保在 StaticFileModule 模块读取文件和服务器之后但在 StaticCompressionModule 之前调用我的后处理/模块?这个问题甚至有意义吗?根据上面的观察,似乎有点矛盾。

【问题讨论】:

  • 我也遇到了同样的问题,我正在工作几个小时来解决它。 :(你能解释一下你是怎么解决这个问题的吗?

标签: iis-7 httpmodule


【解决方案1】:

静态文件压缩配置可以包含特定文件或 mime 类型,我忘记是哪一种了。如果你想使用静态压缩,它只需要在实际上是静态的文件上。您将使用 HttpModule 重写它们的事实意味着它们不再是静态的。因此,您可以对这些文件类型使用动态压缩,并且如您所料,您需要确保您的动态压缩将包含适当的 mime 类型或文件扩展名。

【讨论】:

  • 你是对的。这解决了问题,它实际上更合乎逻辑(它不再是静态文件)。这也表明动态压缩模块 (compdyn.dll) 和静态压缩模块 (compstat.dll) 的区别不仅仅在于它们处理的类型列表。它们必须以不同的方式集成到 IIS 管道中。
猜你喜欢
  • 2012-02-15
  • 2020-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 2015-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多