HTTP响应过滤器无法第二次解码响应字节

时间:2012-06-02 07:53:50

标签: c# iis-7.5 httpresponse httpmodule

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

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

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

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

让我感到困惑的是为什么第一次响应字节被正确解码,但是在第二次请求(即页面刷新)之后它们不是。下面是设置过滤器的编码和过滤器的编写器方法的代码。任何帮助将不胜感激,因为我已经花了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 ?? / ????噩?? V. \ AK T:???????JHY XP,U I Y?   ?\“\ 0 ??? W |????{?] ?? _}!?w ^ ??? \ 0R M Y ?? I7E ???Ž?? 8K ?? 50 8 ???? ??? K ^〜ķ\Ú????˚FLE ????? S = I 10 GQY%22 O ????&LT;???????9X一个BKuZg ??? 4 ?Fq中??? KJ?吨?? 8 ____ $é\?E',?

更新

第一个计时器,所以我不知道如何更新它。所以我正在把我所做的工作缩小/解决问题。

首先,仍然没有喜悦。 : - (

这就是我所做的:

  1. 由于ASP方法可以多次调用Write方法,因此每次在ASP NET调用Write方法时,都会将字节存储在集合中,并将它们添加到集合中
  2. 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方法中,我调用一个方法,对所有收集的字节进行一些处理:

      public override void Flush()  {             byte [] bytesContent = ProcessResponseContent(bytesList);             outputStream.Write(bytesContent,0,bytesContent.Length);             outputStream.Flush(); }

      public 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);
          }
      

      private byte [] 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);
      

      .... .....
      }

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

      返回的bytes数组不受影响,因为代码的目的是将已解码的字符串记录到文件中。

              log("after decoding  " + html);
      

      当我创建UTF8Encoding时,我正在捕获异常。异常被记录到文件中。

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

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

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

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

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

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

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

      我希望这一切都有意义,如果不清楚,请告诉我。我一直在寻找这段代码。

      谢谢,

1 个答案:

答案 0 :(得分:0)

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

strBuffer = Encoding.UTF8.GetString(buffer);

您还假设这将是一组完整的字符 - 它可能包含(比方说)三字节字符中的两个字节。您需要使用Encoder创建Encoding.UTF8来使您的流有状态,以维持调用之间部分书写字符的状态。

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