1、下载获取一般文件内容实现思路
1) 首先需要对ChromiumWebBrowser
的 IRequestHandler
RequestHandler
进行实现。
2) 需要对IRequestHandler
的IResponseFilter
IRequestHandler.GetResourceResponseFilter
方法进行重写。
3) 需要写一个类实现 IResponseFilter
接口。
4) 然后就可用在IResponseFilter
的FilterStatus Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
方法中,读取指定内容的Stream。
2、下载文件示例代码
由于很多文件无法获取到完整内容,再者具体文件内容在Filter里面进行了控制,而Fileter的内容依赖于IRequestHandler
所以,外部只能操作Handler得到数据。 所以需要在,Filter和Hanlder类中,使用事件来传递具体的内容。代码如下。 Filter类如下:
public class TestImageFilter : IResponseFilter
{
public event Action<byte[]> NotifyData;
private int contentLength = 0;
private List<byte> dataAll = new List<byte>();
public void SetContentLength(int contentLength)
{
this.contentLength = contentLength;
}
public FilterStatus Filter(System.IO.Stream dataIn, out long dataInRead, System.IO.Stream dataOut, out long dataOutWritten)
{
try
{
if (dataIn == null)
{
dataInRead = 0;
dataOutWritten = 0;
return FilterStatus.Done;
}
dataInRead = dataIn.Length;
dataOutWritten = Math.Min(dataInRead, dataOut.Length);
dataIn.CopyTo(dataOut);
dataIn.Seek(0, SeekOrigin.Begin);
byte[] bs = new byte[dataIn.Length];
dataIn.Read(bs, 0, bs.Length);
dataAll.AddRange(bs);
if (dataAll.Count == this.contentLength)
{
// 通过这里进行通知
NotifyData(dataAll.ToArray());
return FilterStatus.Done;
}
else if (dataAll.Count < this.contentLength)
{
dataInRead = dataIn.Length;
dataOutWritten = dataIn.Length;
return FilterStatus.NeedMoreData;
}
else
{
return FilterStatus.Error;
}
}
catch (Exception ex)
{
dataInRead = dataIn.Length;
dataOutWritten = dataIn.Length;
return FilterStatus.Done;
}
}
public bool InitFilter()
{
return true;
}
}
bool IRequestHandler.OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
//NOTE: You cannot modify the response, only the request
// You can now access the headers
//var headers = response.ResponseHeaders;
try
{
var content_length = int.Parse(response.ResponseHeaders["Content-Length"]);
if (this.filter != null)
{
this.filter.SetContentLength(content_length);
}
}
catch { }
return false;
}
private TestImageFilter filter = null;
public event Action<byte[]> NotifyData;
IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
var url = new Uri(request.Url);
if (url.AbsoluteUri.Contains("http://test.test.com/somehead?"))
{
this.filter = new TestImageFilter();
filter.NotifyData += filter_NotifyData;
return filter;
}
return null;
}
void filter_NotifyData(byte[] data)
{
if (NotifyData != null)
{
NotifyData(data);
}
}
此方法位IRequestHandler
的一部分实现,通过实现函数:IRequestHandler.GetResourceResponseFilter
得到资源文件的长度,然后长度传入Filter,在Filter中控制从而得到整个数据的真正长度。
3、下载分片分段数据文件数据
部分站点,返回数据是分片了的,不能通过Content-Length的长度来判断,程序的Stream是否完成。
所以需要其他方式处理,单个http请求完成的时候,会调用Complete方法,所以可以在此方法中处理。示例代码如下,
public class FilterManager
{
private static Dictionary<string, IResponseFilter> dataList = new Dictionary<string, IResponseFilter>();
public static IResponseFilter CreateFilter(string guid)
{
lock (dataList)
{
var filter = new TestImageFilter();
dataList.Add(guid, filter);
return filter;
}
}
public static IResponseFilter GetFileter(string guid)
{
lock (dataList)
{
return dataList[guid];
}
}
}
//对Stream进行合并
public class TestImageFilter : IResponseFilter
{
public List<byte> dataAll = new List<byte>();
public FilterStatus Filter(System.IO.Stream dataIn, out long dataInRead, System.IO.Stream dataOut, out long dataOutWritten)
{
try
{
if (dataIn == null || dataIn.Length == 0)
{
dataInRead = 0;
dataOutWritten = 0;
return FilterStatus.Done;
}
dataInRead = dataIn.Length;
dataOutWritten = Math.Min(dataInRead, dataOut.Length);
dataIn.CopyTo(dataOut);
dataIn.Seek(0, SeekOrigin.Begin);
byte[] bs = new byte[dataIn.Length];
dataIn.Read(bs, 0, bs.Length);
dataAll.AddRange(bs);
dataInRead = dataIn.Length;
dataOutWritten = dataIn.Length;
return FilterStatus.NeedMoreData;
}
catch (Exception ex)
{
dataInRead = dataIn.Length;
dataOutWritten = dataIn.Length;
return FilterStatus.Done;
}
}
public bool InitFilter()
{
return true;
}
}
//IRequestHandler实现代码
public class RequestHandler : IRequestHandler
{
// 略去代码 ...
public event Action<byte[]> NotifyMsg;
IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
{
var url = new Uri(request.Url);
if (url.AbsoluteUri.Contains("https://res.wx.qq.com/zh_CN/htmledition/v2/css/base/base2e4e03.css"))
{
var filter = FilterManager.CreateFilter(request.Identifier.ToString());
return filter;
}
return null;
}
void filter_NotifyData(byte[] data)
{
if (NotifyMsg != null)
{
NotifyMsg(data);
}
}
void IRequestHandler.OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)
{
if (request.Url.Contains("https://res.wx.qq.com/zh_CN/htmledition/v2/css/base/base2e4e03.css"))
{
var filter = FilterManager.GetFileter(request.Identifier.ToString()) as TestImageFilter;
filter_NotifyData(filter.dataAll.ToArray());
}
}
}
相关文档:
https://github.com/cefsharp/CefSharp/wiki/Quick-Start
.Net(C#) cefsharp Chrome 浏览器控件后台执行Iframe中的Js代码的方法