HTTP响应过滤器无法第二次解码响应字节
我开发了一个IIS 7 HttpModule。 我的目标是检查特定标签的响应内容。 如果找到标签,则会记录一些内容。
为了实现我的目标,我开发了一个定制的ASP NET Response Filter。 此过滤器扩展了.NET Stream类。
过滤器在OnPreRequestHandlerExecute(Object source,EventArgs e)事件上注册。
HTTP模块已被正确注册。 过滤器正在工作。 问题是,当我刷新页面时,写入写入(byte []缓冲区,int偏移量,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 ???? -6 K -1 ^〜ķ?ú???? F·LE ????? S = I 10 GQY%22 O ???? <9X ??? BKuZg?一个??? 4? FQ ??? KJ?吨?? 8 ?????????? $é?é?,?
更新 。
第一个计时器,所以我不知道如何更新这个。 所以我正在把我所做的努力缩小/解决问题。
首先,仍然没有喜悦。 :-(
这就是我所做的:
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);
}
在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);
.... .....
}
ProcessResponseContent是一种愚蠢的方法。 它只是将字节列表转换为字节数组; 这个字节数组被解码成一个字符串。 现在,我们不应该有任何问题,因为我们获得了在响应中发送的所有字节(bytesList(List)),
由于代码的目的是将解码后的字符串登录到文件中,所以字节数组不会返回。
log("after decoding " + html);
当我创建一个UTF8Encoding时,我正在捕获一个异常。 异常会被记录到文件中。
第一次获取html页面时,内容会记录到文件中。
当我刷新页面(Ctrl + F5)时会记录一个异常:
“发生异常无法将索引0处的字节[8B]从指定的代码页转换为Unicode”
请记住,我的html页面内容非常小。 所有响应内容都在一个块上处理。
第一次访问页面时,接收到的字节数是2805.恰好在这些字节被解码为字符串之前。
第二次调用页面(Ctrl + F5)时,收到的数字字节在被解码之前是1436。
为什么响应的字节数较少,我不确定。 这可能会影响解码操作。
我希望这一切都有意义,请让我知道如果有什么不明确的。 我一直在寻找这个代码很长一段时间。
谢谢,
很难判断这是否是所有问题,但是您忽略了Write
的offset
和count
参数,而是假设整个缓冲区都是有效的:
strBuffer = Encoding.UTF8.GetString(buffer);
你还假设这将是一组完整的字符 - 它可能包含(比方说)三字节字符中的两个字节。 您需要使您的数据流成为有状态,并使用Encoding.UTF8
创建的Encoding.UTF8
Encoder
来维护调用之间部分写入字符的状态。
还要注意,你假设你会在一次调用中获得整个</html>
- 而你可以在一次调用中获得</
,在下一次获得html>
。 有可能ASP.NET真的只会给你打一次电话,但你可能不应该认为是这种情况。
上一篇: HTTP Response filter can't decode the response bytes the second time