1

我有一些旧网站,每个网站都有很多静态 HTML 页面。我想使用 IIS 模块来捕获生成的页面内容并添加额外的 HTML 片段以使其具有新的页眉和页脚(这称为装饰器模式)。这是我的模块代码。奇怪的是,在许多测试中,我注意到该模块被调用了两次当页面被加载并且每次调用将页面的部分内容传递给模块时(第一次调用传递页面的顶部,第二次调用传递页面的剩余部分)。我知道模块被调用两次的原因是因为我使用了一个静态变量来捕获调用次数并将其显示在新的页眉和页脚中(两个数字不同,页脚编号始终比页眉编号大 1)。我还能够将页面内容导出到两个不同的文件中来证明这一点。

namespace MyProject
{
    public class MyModule : IHttpModule
    {
        public void Dispose()
        {
        }

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

        public String ModuleName
        {
            get { return "MyProject"; }
        }

        public void My_Wrapper(Object source, EventArgs e)
        {
            HttpApplication app = (HttpApplication)source;
            HttpContext context = app.Context;
            HttpRequest request = context.Request;
            string requestPath = request.Path.ToString();

            //I have guarding code here so that the following code only applies to 
            //web requests that has ".html" in the end.

            HttpContext.Current.Response.Filter = new WrapperFilter(HttpContext.Current.Response.Filter);
        }
    }

    public class WrapperFilter : MemoryStream
    {
        private static Regex startOfBody = new Regex("(?i)<body(([^>])*)>", RegexOptions.Compiled | RegexOptions.Multiline);
        private static Regex endOfBody = new Regex("(?i)</body>", RegexOptions.Compiled | RegexOptions.Multiline);

        private Stream outputStream = null;

        private static int index = 0;

        public WrapperFilter(Stream output)
        {
            outputStream = output;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            string contentInBuffer = UTF8Encoding.UTF8.GetString(buffer);
            string page = new StringBuilder(contentInBuffer).ToString();
            byte[] outputBuffer = null;
            Match matchStartOfBody = null;
            Match matchEndOfBody = null;

            index++;

            matchStartOfBody = startOfBody.Match(page);
            string header = "html snippets for header: " + index;
            page = startOfBody.Replace(page, "<body " + matchStartOfBody.Groups[1] + ">" + header);

            matchEndOfBody = endOfBody.Match(page); 
            string footer = "html snippets for footer: " + index;
            page = endOfBody.Replace(page, footer + "</body>");

            outputBuffer = UTF8Encoding.UTF8.GetBytes(page);
            outputStream.Write(outputBuffer, 0, outputBuffer.Length);
        }
    }
}

问题:

  1. 模块加载两次的原因是页面内容太大还是需要增加缓存?如果是这样,怎么做?

  2. 从技术上讲,我的方法行得通吗?我能够装饰 HTML 页面,并且由于两个调用过程,我无法处理一些高级情况。

  3. 当图像需要显示在浏览器页面中,并且对图像的请求通过 IIS 模块?

更新

根据来自 usr 的宝贵意见,“奇怪”行为只是 IIS 的正常行为。由于他/她的建议,我添加了一个类变量:

private byte[] allContent = new byte[0];

以及以下更新的方法:

    public override void Write(byte[] buffer, int offset, int count)
    {
        //new bigger array
        byte[] newArr = new byte[allContent.Length + buffer.Length];
        //copy old content
        System.Array.Copy(allContent, newArr, allContent.Length);
        //append new content
        System.Array.Copy(buffer, 0, newArr, allContent.Length, buffer.Length);
        //reset current total content
        allContent = newArr;
    }

并添加一个新方法,其中包含从我之前的 Write 方法中复制的所有代码:

    protected override void Dispose(bool disposing)
    {
    //code copied from my earlier code, with "buffer" changed to "allContent".
    }

现在一切正常!谢谢楼主!!!

4

1 回答 1

1

好的,我应该早点解决这个问题。我承认我没有阅读问题的每一句话。我应该对测量产生怀疑。原来测量被破坏了。

感谢您询问有关页面大小是否重要的​​问题。我又做了测试。确实如此。对于小页面,我在页眉和页脚中看到相同的数字。对于大页面,我看到 3 和 4 或类似的东西。

然后:

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

        index++;

Write可能被调用任意次数。这是一个Stream实现。任何人都可以随心所欲地打电话Stream.Write。你会期望任何Stream.

索引可以每页增加多次。计数代码被破坏,其余的工作。

此外,UTF-8 处理被破坏,因为您不能在任意边界分割 UTF-8 编码数据。

于 2016-03-22T18:25:36.593 回答