寫 ASP.NET 有時候會想要在畫面輸出前一刻進行攔截,並換掉 html 中的特定字元。例如網站中有許多頁面都有 www.google.com.tw 的超連結,我希望在測試機上可以把連結換成 www.microsoft.com.tw ,但又不希望去動到 aspx。這個時候就可以利用 Response.Filter 來做這個事情。
Response.Filter 本身就是一個 Stream 物件,所以要做的事情很簡單,就是再用一個 Stream 把它包起來,然後在 Write 方法加工就行了。為求使用方便,可以再加上 HttpModule 來處理所有 text/html 的回應。
public class CatchText : IHttpModule { void IHttpModule.Dispose() { } void IHttpModule.Init(HttpApplication context) { //註冊事件,在 BeginRequest 的時候把 Response.Filter 換掉 context.BeginRequest += (sender, e) => { context.Response.Filter = new CatchTextStream(context.Response.Filter); }; } } public class CatchTextStream : Stream { private Stream output; public CatchTextStream(Stream s) { output = s; } public override bool CanRead { get { return output.CanRead; } } public override bool CanSeek { get { return output.CanSeek; } } public override bool CanWrite { get { return output.CanWrite; } } public override void Flush() { output.Flush(); } public override long Length { get { return output.Length; } } public override long Position { get { return output.Position; } set { output.Position = value; } } public override int Read(byte[] buffer, int offset, int count) { return output.Read(buffer, offset, count); } public override long Seek(long offset, SeekOrigin origin) { return output.Seek(offset, origin); } public override void SetLength(long value) { output.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { StringComparison ignore = StringComparison.CurrentCultureIgnoreCase; if (HttpContext.Current != null){ HttpContext context = HttpContext.Current; if (context.Response.ContentType.Equals("text/html", ignore)) { Encoding encoding = context.Response.ContentEncoding; //在這邊把 google 換成 microsoft string html = encoding.GetString(buffer, offset, count) .Replace("google", "microsoft"); byte[] bytes = encoding.GetBytes(html); output.Write(bytes, 0, bytes.Length); } else output.Write(buffer, offset, count); } } }
整個程式就只有這樣,主要就是在 Write 方法裡面動點手腳而已,剩下的就是設定 web.config,把這個 HttpModule 掛上去。
<httpModules> <add name="CatchText1" type="CatchText"/> </httpModules>
接著就可以看到效果了