在Module中使用自定义过滤器,来统一对站内所有请求响应的输出内容进行采集或更改。...
1.客户端的IP
2.客户端请求的页面路径
3.客户端发出的请求头
4.服务器返回的正文内容。
在代码设计前分析了一下,前三个都很好解决,对于截获服务器返回的正文,准备用HttpResponse 对象中的Output 和 OutputStream 属性输出信息来解决。
可是在正式编码的过程中,发现Output和OutputStream 并不是想像中可以直接把数据转出取回,耗费了近两天的时间,想尽了一切办法可还是仅仅可以追加内容并无法读取。
在网上查阅到,对于HttpResponse 对象,仅仅可以使用过滤器来对其中将要输出的内容进行修改。
这个过滤器要继承自Stream 类,并要实现其中的虚方法。看来之前企图使用HttpWriter,TextWriter,Stream,HttpStream 这些类来转出数据完全是错误的。
现在有信心来截获服务器返回内容了,说干就干吧!
1.首先要建立一个简易过滤器。
代码如下:
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Web;
/**//// <summary>
/// 定义原始数据EventArgs,便于在截获完整数据后,由事件传递数据
/// </summary>
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;
/**//// <summary>
/// 当原始数据采集成功后激发。
/// </summary>
public event EventHandler<RawDataEventArgs> 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);
//采用正则,检查输入的是否有页面结束符</html>
Regex eof = new Regex("</html>", 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.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
/**//// <summary>
/// 对此HTTP请求处理的过程全部结束
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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<RawDataEventArgs>(filter_OnRawDataRecordedEvent);
}
}
/**//// <summary>
/// 当原始数据采集到以后,入库
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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 中增加配置节如下:
<httpModules>
<add name="RawDataModule" type="HttpRawDataModule"/>
</httpModules>
</system.web>
测试成功,能准确的获得服务器向客户端输出的HTML内容。
其中,在过滤器中,可以直接对即将要输出的内容做 对于字符串的任意处理。
而且采用这样的方式来对站点即将输出的内容做修改和采集,可以通过修改配置文件,随时打开和关闭,有很强的优越性和灵活性还有重用性。
记得看到过很多需要产生静态页面的网站,都是通过代码HttpWebRequest 向自己请求并记录返回的代码产生静态页面,不知道我当前介绍的方法是否更好写,比如需要产生静态页面时,不管是谁发出请求,由服务器检查自己是否有静态页面,否则产生静态页面,并转向。给出引子,希望大家还是自己开阔思路比较好。
这里我还想到一个额外的使用场景,比如入侵到一台支撑IIS 的服务器,上传自定义的过滤器和自定义的HttpModule 库,修改对方站点内的配置文件使之生效,就可以轻松做到窃取客户端输入内容和输出内容。不过修改配置文件不知道会不会让人容易发觉呀???
^_^
转载于:https://www.cnblogs.com/SUNBOY/archive/2007/05/31/766607.html
在Module中使用自定义过滤器,来统一对站内所有请求响应的输出内容进行采集或更改。...相关推荐
- MVC中的自定义过滤器
过滤器的类型 ASP.NET MVC 框架支持以下几种过滤器: 1.Authorization 过滤器– 实现了 IAuthorizationFilter 接口.这一类的过滤器用来实现用户验证 ...
- Vue中使用自定义过滤器转换Unix时间戳
从后台得到的json数据中使用了unix格式的时间戳,前台使用vue展示的时候可以用过滤器对模板中的标签进行处理,很是方便,实现过程: 1.注册自定义过滤器 <script>//注册自定义 ...
- .NET Core中使用结果过滤器ResultFilter统一结果返回封装
介绍 实现需要继承IResultFilter或者 IAsyncResultFilter. 为了方便开发,简化代码,也为了与前端方便对接,需要对接口服务返回结果进行统一处理 定义统一返回的结果类 我们需 ...
- Java Web开发中,自定义过滤器被执行两次的原因分析及解决办法
本文出处:http://blog.csdn.net/chaijunkun/article/details/7646338,转载请注明.由于本人不定期会整理相关博文,会对相应内容作出完善.因此强烈建议在 ...
- es自建搜索词库_ElasticSearch-IK拓展自定义词库(2):HTTP请求动态热词内容方式...
上一章节(https://my.oschina.net/jsonyang/blog/1643032)我们介绍了使用热词文件形式拓展词库,这样的好处是方便简单,但是如果公司运营人员来直接管理这个东西的话 ...
- springboot项目中使用shiro 自定义过滤器和token的方式___shiro使用token登录流程
springboot项目中使用shiro 自定义过滤器和token的方式 实现步骤主要是以下几步: 1. 在项目中导入maven依赖 <dependency><groupId> ...
- ThinkPHP6.0使用twig作为模板引擎及自定义过滤器
ThinkPHP自带的模板引擎用起来很不顺手,好在找到了一个和Jinja2很类似的一个一个模板引擎Twig,可以集成到ThinkPHP中. 文档: https://github.com/yunwuxi ...
- python数据处理常用函数_pytorch中的自定义数据处理详解
pytorch在数据中采用Dataset的数据保存方式,需要继承data.Dataset类,如果需要自己处理数据的话,需要实现两个基本方法. :.getitem:返回一条数据或者一个样本,obj[in ...
- python构造自定义数据包_pytorch中的自定义数据处理详解
pytorch在数据中采用Dataset的数据保存方式,需要继承data.Dataset类,如果需要自己处理数据的话,需要实现两个基本方法. :.getitem:返回一条数据或者一个样本,obj[in ...
最新文章
- android 封装的popwindow,Android UI开发 popupwindow介绍以及代码实例
- linux 程序读写Env分区 --- mtdparts,/dev/mtd*,mtd_debug
- Linux服务器集群系统(三)--转
- 21世纪初最有影响力的20篇计算机视觉期刊论文
- 投资者建议三星电子一分为二 股价创历史新高
- T5: Text-to-Text Transfer Transformer 阅读笔记
- 初始化Dictionarystring, object赋值
- 使用ultramon调整任务栏高度
- 来了,单片机最强科普总结!
- 回忆一 --- 去年6月面试进入公司的日子
- java高级教程_高级Java教程
- php 非常有用的高级函数PATH_SEPARATOR常量和set_include_path
- shell统计指定目录下所有文件类型及数量
- 通过yum安装Nagios
- Android大学课件SQLite3 数据库操作
- Oracle数据库下载安装教程
- 全面解读人工智能、大数据和云计算的关系
- python金融编程入门_python金融实务从入门到精通完整版
- 迅捷在线PDF转换成Word转换器简介
- 纯音乐 -《抒情中国系列-烟雨江南》
热门文章
- 超融合平台安装oracle,超融合平台集成实施方案
- jdbctemplate 新增数据 返回主键id
- 【转载】Linux 命令行快捷键 - 移动光标
- Material Design组件之NavigationView
- 互联网公司面试必问的mysql题目
- 使用docker安装设置oracle
- 安装构建以太坊钱包Parity
- 人造电子皮肤、软体机器人、单孔腔镜手术机器人......青年科学家们都在研究哪些“黑科技”?...
- 点击页面的悬浮窗口实现随意拖动
- python 序列类型函数_序列类型可用的内置函数