我开发了一个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',?
更新
第一个计时器,所以我不知道如何更新它。所以我正在把我所做的工作缩小/解决问题。
首先,仍然没有喜悦。 : - (
这就是我所做的:
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)中获得了响应发送的所有字节
返回的bytes数组不受影响,因为代码的目的是将已解码的字符串记录到文件中。
log("after decoding " + html);
当我创建UTF8Encoding时,我正在捕获异常。异常被记录到文件中。
首次检索html页面时,内容会记录到文件中。
当我刷新页面(Ctrl + F5)时,会记录一个异常:
“异常发生无法将索引0处的字节[8B]从指定代码页转换为Unicode”
请记住,我的html页面内容非常小。所有响应内容都在一个块上处理。
第一次访问页面时,收到的字节数是2805.就在这些字节被解码为字符串之前。
第二次调用页面时(Ctrl + F5),在解码之前收到的字节数为1436。
为什么响应的字节数较少,我不确定。 这可能会影响解码操作。
我希望这一切都有意义,如果不清楚,请告诉我。我一直在寻找这段代码。
谢谢,
答案 0 :(得分:0)
很难判断这是否是所有问题,但您忽略了offset
中的count
和Write
参数,而是假设整个缓冲区都有效:
strBuffer = Encoding.UTF8.GetString(buffer);
您还假设这将是一组完整的字符 - 它可能包含(比方说)三字节字符中的两个字节。您需要使用Encoder
创建Encoding.UTF8
来使您的流有状态,以维持调用之间部分书写字符的状态。
另请注意,您假设在一次通话中将获得整个</html>
- 而您可以在一次通话中获得</
,在下一次通话中获得html>
。 ASP.NET 真的可能只会在最后调用一次,但您可能不应该认为是这种情况。