截獲asp.net http輸出資料流自己做處理

來源:互聯網
上載者:User

Asp.net2.0 中自訂過濾器對Response內容進行處理2007-11-17      來源:e800.net頻道         作者:來自:conanpaul 關鍵詞:  Response     處理     內容     定義  

2007-11-5

因項目需要,對每一個訪問網站的請求要做未經處理資料記錄,其中要包括幾個要素:
1.用戶端的IP
2.用戶端請求的頁面路徑
3.用戶端發出的要求標頭
4.伺服器返回的本文內容。

在代碼設計前分析了一下,前三個都很好解決,對於截獲伺服器返回的本文,準備用HttpResponse 對象中的Output 和 OutputStream 屬性輸出資訊來解決。

可是在正式編碼的過程中,發現Output和OutputStream 並不是想像中可以直接把資料轉出取回,耗費了近兩天的時間,想盡了一切辦法可還是僅僅可以追加內容並無法讀取。

在網上查閱到,對於HttpResponse 對象,僅僅可以使用過濾器來對其中將要輸出的內容進行修改。
這個過濾器要繼承自Stream 類,並要實現其中的虛方法。看來之前企圖使用HttpWriter,TextWriter,Stream,HttpStream 這些類來轉出資料完全是錯誤的。

現在有信心來截獲伺服器返回內容了,說幹就幹吧!

1.首先要建立一個簡易過濾器。
代碼如下:
using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.IO; 
using System.Web;

/**//// 
/// 定義未經處理資料EventArgs,便於在截獲完整資料後,由事件傳遞資料
/// 
public class RawDataEventArgs : EventArgs
{
private string sourceCode;

public RawDataEventArgs(string SourceCode)
{
sourceCode = SourceCode; 
}
public string SourceCode
{
get { return sourceCode; }
set { sourceCode = value; }
}
}

//自訂過濾器
public class RawFilter : Stream
{

Stream responseStream; 
long position; 
StringBuilder responseHtml;

/**//// 
/// 當未經處理資料採集成功後激發。
/// 
public event EventHandler OnRawDataRecordedEvent;

public RawFilter(Stream inputStream)
{
responseStream = inputStream; 
responseHtml = new StringBuilder(); 
}

//實現Stream 虛方法
Filter Overrides#region Filter Overrides

public override bool CanRead
{
get
{
return true; 
}
}

public override bool CanSeek
{
get
{
return true; 
}
}

public override bool CanWrite
{
get
{
return true; 
}
}
public override void Close()
{
responseStream.Close(); 
}

public override void Flush()
{
responseStream.Flush(); 
}

public override long Length
{
get
{
return 0; 
}
}

public override long Position
{
get
{
return position; 
}
set
{
position = value; 
}
}

public override int Read(byte[] buffer, int offset, int count)
{
return responseStream.Read(buffer, offset, count); 
}

public override long Seek(long offset, SeekOrigin origin)
{
return responseStream.Seek(offset, origin); 
}

public override void SetLength(long length)
{
responseStream.SetLength(length); 
}
#endregion

//關鍵的點,在HttpResponse 輸入內容的時候,一定會調用此方法輸入資料,所以要在此方法內截獲資料
public override void Write(byte[] buffer, int offset, int count)
{
string strBuffer = System.Text.UTF8Encoding.UTF8.GetString(buffer, offset, count);

//採用正則,檢查輸入的是否有頁面結束符
Regex eof = new Regex("", RegexOptions.IgnoreCase);

if (!eof.IsMatch(strBuffer))
{
//頁面沒有輸出完畢,繼續追加內容
responseHtml.Append(strBuffer); 
}
else
{
//頁面輸出已經完畢,截獲內容
responseHtml.Append(strBuffer); 
string finalHtml = responseHtml.ToString();

//激發資料已經擷取事件
OnRawDataRecordedEvent(this, new RawDataEventArgs(finalHtml));

//繼續傳遞要發出的內容寫入流
byte[] data = System.Text.UTF8Encoding.UTF8.GetBytes(finalHtml);

responseStream.Write(data, 0, data.Length); 
}
}
}
至此,過濾器定義完畢了,接下來還需要把這個過濾器裝配到HttpResponse 對象中。
為了能夠截獲整站的aspx 頁面輸出的內容,我們可以定義一個HttpModule 來完成。
代碼如下:

using System; 
using System.Web; 
using System.Collections.Generic; 
using System.Text; 
using System.IO; 
using System.Diagnostics;

public class HttpRawDataModule : IHttpModule
{
IHttpModule 成員#region IHttpModule 成員

public void Dispose()
{

}

public void Init(HttpApplication context)
{
//綁定事件,在對此請求處理過程全部結束後進行過濾操作
context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState); 
}

#endregion

/**//// 
/// 對此HTTP請求處理的過程全部結束
/// 
/// 
/// 
void context_ReleaseRequestState(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;

//這裡需要針對ASPX頁面進行攔截,測試發現如果不這麼做,Wap 訪問網站圖片容易顯示為X,奇怪
string[] temp = application.Request.CurrentExecutionFilePath.Split(''.''); 
if (temp.Length > 0 && temp[temp.Length - 1].ToLower() == "aspx")
{
//裝配過濾器
application.Response.Filter = new RawFilter(application.Response.Filter);

//綁定過濾器事件
RawFilter filter = (RawFilter)application.Response.Filter; 
filter.OnRawDataRecordedEvent += new EventHandler(filter_OnRawDataRecordedEvent); 
}
}

/**//// 
/// 當未經處理資料採集到以後,入庫 
/// 
/// 
/// 
void filter_OnRawDataRecordedEvent(object sender, RawDataEventArgs e)
{
string allcode = e.SourceCode; 
WapSite.SiteDataClass wapdata = new WapSite.SiteDataClass(); 
wapdata.WriteRawDataLog(allcode); 
}
}

HttpModule 準備完畢,也裝配上了過濾器,接下來還需要在設定檔中配置HttpModules配置節 ,把自訂的HttpModule 加入到HTTP處理管道中。
在Web.config 中增加配置節如下:

測試成功,能準確的獲得伺服器向用戶端輸出的HTML內容。

其中,在過濾器中,可以直接對即將要輸出的內容做 對於字串的任意處理。

而且採用這樣的方式來對網站即將輸出的內容做修改和採集,可以通過修改設定檔,隨時開啟和關閉,有很強的優越性和靈活性還有重用性。

記得看到過很多需要產生靜態頁面的網站,都是通過代碼HttpWebRequest 向自己請求並記錄返回的代碼產生靜態頁面,不知道我當前介紹的方法是否更好寫,比如需要產生靜態頁面時,不管是誰發出請求,由伺服器檢查自己是否有靜態頁面,否則產生靜態頁面,並轉向。給出引子,希望大家還是自己開闊思路比較好。

這裡我還想到一個額外的使用情境,比如入侵到一台支撐IIS 的伺服器,上傳自訂的過濾器和自訂的HttpModule 庫,修改對方網站內的設定檔使之生效,就可以輕鬆做到竊取用戶端輸入內容和輸出內容。不過修改設定檔不知道會不會讓人容易發覺呀???

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.