1

我开发了一个 IIS 7 HttpModule。我的目标是检查特定标签的响应内容。如果找到标签,则记录一些内容。

为了实现我的目标,我开发了一个定制的 ASP NET 响应过滤器。此过滤器扩展了 .NET Stream 类。

过滤器在 OnPreRequestHandlerExecute(Object source, EventArgs e) 事件上注册。

HTTP 模块已正确注册。过滤器正在工作。问题是,当我刷新页面时,Write the Write(byte[] buffer, int offset, int count) 方法被按预期调用,但是,解码它们时字节的内容是 gobbledygook。

这让我很困惑,为什么第一次响应字节被正确解码,但是在第二次请求(即页面刷新)之后它们却没有。下面是设置过滤器的代码和过滤器的 writer 方法的代码。任何帮助将不胜感激,因为我已经花了 3 天,调试,在谷歌上研究,但仍然没有快乐。

public void OnPreRequestHandlerExecute(Object source, EventArgs e)
{

    HttpResponse response = HttpContext.Current.Response;
    if (response.ContentType == "text/html")
    {
        response.ContentEncoding = Encoding.UTF8; //forcing encoding UTF8
        response.Charset = "charset=utf-8";
        Encoding encoding = response.ContentEncoding;
        string encodingName = encoding.EncodingName;
        response.Filter = new MyFilter(response.Filter, response.ContentEncoding);
    }
}

    public override void Write(byte[] buffer, int offset, int count)
    {
        string strBuffer = string.Empty;

        try
        {
            strBuffer = Encoding.UTF8.GetString(buffer);
        }
        catch (EncoderFallbackException ex)
        {
            log(ex.Message);
        }


        // buffer doesn't contain the HTML end tag so we keep storing the 
        //incoming chunck of data

        if (!strBuffer.Contains("</html>"))
        {
            log(strBuffer.ToString() );
            _responseHtml.Append(strBuffer);

        }
        //the strbuffer contains the HTLM end tag ; we wrap it up now
  else
        {
            _responseHtml.Append(strBuffer); //append last chunck of data
            string finalHtml = _responseHtml.ToString();


               byte[] bytesBuffer = Encoding.UTF8.GetBytes(finalHtml);
                outputStream.Write(bytesBuffer, 0, bytesBuffer.Length);
            }

        }

    }

这就是我得到的,在解码响应字节后,第二次调用 html 页面(即在浏览器上刷新)

?\b\0\0\0\0\0\0?yw??/????Og??V.\ak?t:JhY??xP,u?I?Y? \"?\0???w?|?W???\0R?M?Y??I7E{?]??_}???z??8K??!?5O?8???? ??k?^?~k\?u????f?lE??????s=i??gqY%??O????<9x???BKuZg?a???4? Fq???KJ?t??8??????????$e\?E?,?

更新

第一个计时器,所以我不确定如何更新它。所以我把我所做的事情缩小/解决问题。

首先,还是No Joy。:-(

这就是我所做的:

  1. 由于 ASP NET 可以多次调用 Write 方法,因此我将字节存储在一个集合中,并将它们添加到集合中,每次 ASP NET 调用 Write 方法时

p

ublic override void Write(byte[] buffer, int offset, int count)
                {

                        for (int i = 0; i < count; i++)
                        {
                            bytesList.Add(buffer[i]);
                        }
                        log("Write was called "+ "number of bytes: "+ bytesList.Count + " - " + count);
                }
  1. 在 flush 方法上,我调用了一个对收集的所有字节执行一些工作的方法:

    公共覆盖 void Flush() { byte[] bytesContent = ProcessResponseContent(bytesList); outputStream.Write(bytesContent, 0, bytesContent.Length); outputStream.Flush(); }

    公共覆盖无效写入(字节[]缓冲区,整数偏移量,整数计数){

            for (int i = 0; i < count; i++)
            {
                bytesList.Add(buffer[i]);
            }
            log("Write was called " + "number of bytes: " + bytesList.Count + " -" + count);
        }
    

    私有字节[] ProcessResponseContent(List bytesList) {

           byte[] bytesArray = bytesList.ToArray();
            string html = string.Empty;
            byte[] encodedBytes = null;
    
            try
            {
                FilterEncoder encoder = new FilterEncoder();
                html = encoder.DecodeBytes(bytesArray.Length, bytesArray);
                encodedBytes = encoder.EncodeString(html);
                log("after encoding - encodedBytes" + encodedBytes.Length);
                log("after encoding - bytesArray" + bytesArray.Length);
            }
            catch (Exception ex)
            {
                log("exception ocurred " + ex.Message);
    

    ...... ......
    }

ProcessResponseContent 是一个愚蠢的方法。它只是将字节列表转换为字节数组;这个字节数组被解码成一个字符串。现在我们应该没有任何问题,因为我们在 bytesList (List ) 中获得了响应中发送的所有字节

字节数组原封不动地返回,因为代码的目的是将解码后的字符串登录到文件中。

        log("after decoding  " + html);

当我创建一个 UTF8Encoding 时,我遇到了一个异常。异常被记录到文件中。

第一次检索 html 页面时,内容会记录到文件中。

当我刷新页面(Ctrl + F5)时,会记录一个异常:

“发生异常无法将索引 0 处的字节 [8B] 从指定代码页转换为 Unicode”

请记住,我的 html 页面内容非常小。所有响应内容都在一个块上处理。

第一次访问页面时收到的字节数是 2805。就在这些字节被解码为字符串之前。

第二次调用页面 (Ctrl + F5) 接收到的字节数在解码之前是 1436。

为什么响应的字节数较少,我不确定。这可能会影响解码操作吗?

我希望这一切都有意义,如果有不清楚的地方,请告诉我。我一直在寻找这段代码很长时间。

谢谢,

4

1 回答 1

0

很难判断这是否是问题的全部,但您忽略了 中的offsetandcount参数Write,而是假设整个缓冲区都是有效的:

strBuffer = Encoding.UTF8.GetString(buffer);

您还假设这将是一组完整的字符 - 它可能包含(比如说)三个字节字符中的两个字节。您需要使您的流有状态,并使用Encodercreated fromEncoding.UTF8来维护调用之间部分写入字符的状态。

另请注意,您假设您将</html>在一次通话中获得全部 - 而您可以</在一次通话中获得,然后html>在下一次通话中获得。ASP.NET 可能真的只在最后调用一次,但您可能不应该假设是这种情况。

于 2012-06-02T08:10:05.303 回答