chromiumwebbrowser 使用_CefSharp.ChromiumWebBrowser浏览器的一些功能使用

本文介绍了如何在CefSharp的ChromiumWebBrowser中配置AnyCpu编译,使用Http代理服务,实现每个实例独立的Cookie隔离,并通过IResponseFilter获取响应数据。详细讲解了代码实现过程,包括动态加载程序集、设置代理、管理Cookie以及拦截响应内容的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.配置支持AnyCpu编译模式

CefSharp从51版本以后开始支持AnyCpu编译模式,首先需要在当前项目的csproj文件的PropertyGroup节点下第一行增加一个配置项

true

然后在程序的启动入口配置动态加载目标平台x86/x64的程序集:

[STAThread]

static void Main()

{

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

AppDomain.CurrentDomain.AssemblyResolve += Resolver;

Application.Run(new Form1());

}

private static Assembly Resolver(object sender, ResolveEventArgs args)

{

if (args.Name.StartsWith("CefSharp"))

{

string assemblyName = args.Name.Split(new[] { ',' }, 2)[0] + ".dll";

string archSpecificPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,

Environment.Is64BitProcess ? "x64" : "x86",

assemblyName);

return File.Exists(archSpecificPath)

? Assembly.LoadFile(archSpecificPath)

: null;

}

return null;

}

这种方法是根据运行的目标平台动态去加载对应的程序集,如果我们能明确运行平台则可以不用加上面的代码逻辑,在当前项目App.config文件的根节点下加入以下配置即可:

2.使用Http代理服务

网上一些文章介绍的通过添加命令行参数CefCommandLineArgs的方式,我试了一下不管用,通过 CefSharpSettings.Proxy = new ProxyOptions("ipadress", "prot", "username", "password"); 这句是可以配置成功的,但这个是全局配置,不能满足独立我要控制每个browser实例各自使用自己的代理服务器。通过在初始化ChromiumWebBrowser的地方加入以下代码可实现动态设置代理。

var browser = new ChromiumWebBrowser("url", context);

browser.RequestHandler = new DefaultRequestHandler();

Cef.UIThreadTaskFactory.StartNew(delegate

{

var rc = browser.GetBrowser().GetHost().RequestContext;

rc.GetAllPreferences(true);

var dict = new Dictionary();

dict.Add("mode", "fixed_servers");

dict.Add("server", "ipaddress:prot"); //此处替换成实际 ip地址:端口 string error;

bool success = rc.SetPreference("proxy", dict, out error);

if (!success)

{

Console.WriteLine("something happen with the prerence set up" + error);

}

});

如果代理服务有用户名密码的话,则需要在DefaultRequestHandler类里重写GetAuthCredentials方法,如下:

protected override bool GetAuthCredentials(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)

{

if (isProxy)

{

callback.Continue("username", "passwrod");

return true;

}

return false;

}

这样就可以实现每个ChromiumWebBrowser运行实例独立连接自己的代理服务器了。

3.Cookie隔离,每个IWebBrowser实例的数据不共享

要保证多个browser实例之间cookie不共享,就不要在全局设置CefSettings中设置CachePath值,应该在实例的RequestContextSettings中设置,可以设置成每个browser拥有独立的缓存目录。在RequestContext内添加的cookie只有当前browser才能访问,从而实现cookie隔离。

var setting = new RequestContextSettings()

{

CachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CefSharp\\Cache_" + name),

PersistSessionCookies = true,

PersistUserPreferences = true

};

var context = new RequestContext(setting);

var cookieManager = context.GetCookieManager(null);

//这样设置的cookie不是全局的,只有当前browser才能访问 cookieManager.SetCookie("domain", new Cookie

{

Name = "cookiename",

Value = "cookievalue",

Path = "/"

});

var browser = new ChromiumWebBrowser("url", context);

4.使用IResponseFilter获取响应数据

要获取ChromiumWebBrowser中每个请求的响应body内容并不是那么方便,拿到Frame的html内容倒是很简单,使用IFrame的GetSourceAsync()方法就行,但有时候我们需要单个请求的响应结果,这就需要自定义实现IResponseFilter接口来实现响应数据的拦截。

//DefaultResourceHandler的构造可以放在IRequestHandler的实现类的GetResourceRequestHandler方法内  class DefaultResourceHandler : ResourceRequestHandler

{

protected override IResponseFilter GetResourceResponseFilter(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response)

{

if (response.MimeType.Equals("application/json", StringComparison.OrdinalIgnoreCase))

{

return JsonResponseFilter.CreateFilter(request.Identifier.ToString());

}

return null;

}

protected override void OnResourceLoadComplete(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)

{

var filter = JsonResponseFilter.GetFileter(request.Identifier.ToString()) as JsonResponseFilter;

if (filter != null)

{

var encode = !string.IsNullOrEmpty(response.Charset)

? Encoding.GetEncoding(response.Charset)

: Encoding.UTF8;

using (var read = new StreamReader(filter.GetStream(), encode))

{

var text = read.ReadToEnd();

Debug.WriteLine(text);

}

}

}

}

public class JsonResponseFilter : IResponseFilter

{

private MemoryStream Stream;

public JsonResponseFilter()

{

Stream = new MemoryStream();

}

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);

Stream.Write(bs, 0, bs.Length);

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;

}

public Stream GetStream()

{

Stream.Seek(0, SeekOrigin.Begin);

return Stream;

}

public void Dispose()

{

}

private static Dictionary _dictionary = new Dictionary();

public static IResponseFilter CreateFilter(string id)

{

var filter = new JsonResponseFilter();

_dictionary[id] = filter;

return filter;

}

public static IResponseFilter GetFileter(string id)

{

if (_dictionary.ContainsKey(id))

{

var filter = _dictionary[id];

_dictionary.Remove(id);

return filter;

}

return null;

}

}

为了截获响应数据绕了这么一大圈有点费劲,不过人家这种设计也是为了方便外部扩展,可以针对不同响应类型的response来实现IResponseFilter过滤器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值