使用C#在CEF中拦截并响应请求
一、前言
忙里偷闲,研究了一下如何在CEF中拦截请求,并作出响应。这个功能对某些需要修改服务器响应的需求来说必不可少,可以直接读取本地文件作为响应内容。
C#的CEF封装项目有很多,我使用的是ChromiumFx。它的最大特点是采用事件的形式实现接口的效果。这样我们在使用时只需要订阅事件实现功能即可,而不用继承类重写方法,这很苏胡。
二、CEF3接口
简单介绍一下CEF3的接口。
CefClient:回调管理类,包含5个接口用于创建其它的回调类的对象
CefLifeSpanHandler: 回调类,用于控制popup对话框的创建和关闭等操作
CefLoadHandler: 回调类,可以用来监听frame的加载开始,完成,错误等信息
CefRequestHandler: 回调类,用于监听资源加载,重定向等信息
CefDisplayHandler: 回调类,用于监听页面加载状态,地址变化,标题等得信息
CefGeolocationHandler: 回调类,用于CEF3向嵌入者申请geolocation的权限 CefApp: 与进程,命令行参数,代理,资源管理相关的回调类,用于让CEF3的调用者们定制自己的逻辑
CefBrowser: renderer进程中执行浏览相关的类,例如前进,后退等
CefBrowserHost: browser进程中的执行浏览相关的类,其会把请求发送给CefBrowser
CefFrame: 表示的是页面中的一个Frame,可以加载特定url,在该运行环境下执行JavaScript代码等得。
V8:CEF3提供支持V8extension的接口,但是这有两个限制,第一,v8 extension仅在Renderer进程使用;第二,仅在沙箱模型关闭时使用。
三、流程
我们关注的就是上述的CefRequestHandler接口,其中包含了发起请求,读取响应结果的接口方法。
以下内容在ChromiumFx库上实现,使用其它库大致相似。
1. ChromiumWebBrowser提供了RequestHandler类,在GetResourceHandler中可以根据需要指定ResourceHandler实例以实现拦截响应请求,或返回null来使用cef默认的方式处理请求。
2.新建ResourceHandler实例,并指定以下事件发生时的动作:
ProcessRequest 处理请求,允许请求返回true;取消请求返回false。当需要返回的数据就绪后(自行请求网络或者文件就绪)或立即调用callback.Continue(),通知cef进入下一步:GetResponseHeaders。
GetResponseHeaders 设置响应头,在这里可以设置mime-type,响应长度,其它头等。不确定长度设置响应长度为-1。
ReadResponse 设置响应结果。可以设置响应具体内容,设置已读取长度。cef调用完上一步后会继续调用此方法。根据响应长度和数据就绪情况,调用此方法的次数和策略不同。
当响应长度为-1时,cef无法根据已读长度确定是否已读取完毕,必需根据返回值false来结束读取。
当响应长度大于0时,cef根据每次调用得到的已读长度,或返回值false来结束读取。
如果数据未就绪,可以设置读取长度为0 ,返回true,并在稍后调用callbak.Continue()通知cef调用此方法读取响应内容。
注意:
当响应长度为-1时,必需保证此方法至少执行两次,第一次返回true表示数据全部就绪,第二次返回false表示读取结束。
当响应长度大于0时,设置内容和已读长度,返回true。则此方法只执行一次。
若实际返回的响应内容,长度大于之前设置的响应总长度,则返回内容将被截取。
四、代码
其中还包括了其它设置和订阅了一些有趣的事件,供参考。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
InitializationChromium();
} private void InitializationChromium()
{
ChromiumWebBrowser.OnBeforeCfxInitialize += ChromiumWebBrowser_OnBeforeCfxInitialize;
ChromiumWebBrowser.OnBeforeCommandLineProcessing += ChromiumWebBrowser_OnBeforeCommandLineProcessing;
ChromiumWebBrowser.Initialize(); ChromiumWebBrowser wb = new ChromiumWebBrowser();
wb.Dock = DockStyle.Fill;
wb.Parent = this;
wb.LoadHandler.OnLoadStart += LoadHandler_OnLoadStart;
wb.LoadHandler.OnLoadEnd += LoadHandler_OnLoadEnd;
wb.DownloadHandler.OnBeforeDownload += DownloadHandler_OnBeforeDownload;
wb.RequestHandler.OnBeforeBrowse += RequestHandler_OnBeforeBrowse;
wb.RequestHandler.GetResourceHandler += RequestHandler_GetResourceHandler;
wb.SetWebResource("http://localresource/html", new Chromium.WebBrowser.WebResource("<html></html>"));
wb.LoadUrl("http://m.baidu.com");
} void RequestHandler_GetResourceHandler(object sender, Chromium.Event.CfxGetResourceHandlerEventArgs e)
{
if (e.Request.Url == "http://m.baidu.com/")
{
CfxResourceHandler handler = new CfxResourceHandler();
handler.ProcessRequest += handler_ProcessRequest;
handler.GetResponseHeaders += handler_GetResponseHeaders;
handler.ReadResponse += handler_ReadResponse; e.SetReturnValue(handler);
}
else
{
e.SetReturnValue(null);
}
} void handler_ProcessRequest(object sender, Chromium.Event.CfxProcessRequestEventArgs e)
{
e.Callback.Continue();
e.SetReturnValue(true);
} void handler_GetResponseHeaders(object sender, Chromium.Event.CfxGetResponseHeadersEventArgs e)
{
e.ResponseLength = -1;
e.Response.MimeType = "text/html";
e.Response.Status = 200;
} int count = 0;
void handler_ReadResponse(object sender, Chromium.Event.CfxReadResponseEventArgs e)
{
if (count == 0)
{
byte[] data = Encoding.UTF8.GetBytes("<html><body><h1>Hello CEF</h1></body></html>");
e.BytesRead = data.Length;
Marshal.Copy(data, 0, e.DataOut, data.Length);
e.SetReturnValue(true);
count++;
}
else
{
e.SetReturnValue(false);
}
} void RequestHandler_OnBeforeBrowse(object sender, Chromium.Event.CfxOnBeforeBrowseEventArgs e)
{
if (e.Request.Url == "")
{
e.SetReturnValue(true);
}
} void DownloadHandler_OnBeforeDownload(object sender, Chromium.Event.CfxOnBeforeDownloadEventArgs e)
{
e.Callback.Continue("d:\\" + e.SuggestedName, false);
} void LoadHandler_OnLoadEnd(object sender, Chromium.Event.CfxOnLoadEndEventArgs e)
{
//MessageBox.Show("end loading" + e.Frame.Url);
//MessageBox.Show("is main:" + e.Frame.IsMain);
e.Frame.SelectAll();
} void LoadHandler_OnLoadStart(object sender, Chromium.Event.CfxOnLoadStartEventArgs e)
{
//MessageBox.Show("start loading"+e.Frame.Url);
} void ChromiumWebBrowser_OnBeforeCommandLineProcessing(Chromium.Event.CfxOnBeforeCommandLineProcessingEventArgs e)
{
e.CommandLine.AppendSwitch("--disable-web-security");
} void ChromiumWebBrowser_OnBeforeCfxInitialize(Chromium.WebBrowser.Event.OnBeforeCfxInitializeEventArgs e)
{
e.Settings.CachePath = "Session";
e.Settings.Locale = "zh-CN";
} private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
CfxRuntime.Shutdown();
}
}
响应长度已知的情况:
void handler_GetResponseHeaders(object sender, Chromium.Event.CfxGetResponseHeadersEventArgs e)
{
e.ResponseLength = Encoding.UTF8.GetBytes("<html><body><h1>Hello CEF</h1></body></html>").Length;
e.Response.MimeType = "text/html";
e.Response.Status = ;
} void handler_ReadResponse(object sender, Chromium.Event.CfxReadResponseEventArgs e)
{
byte[] data = Encoding.UTF8.GetBytes("<html><body><h1>Hello CEF</h1></body></html>");
e.BytesRead = data.Length;
Marshal.Copy(data, , e.DataOut, data.Length);
e.SetReturnValue(true);
}
最终效果如下:

综上所述,虽然学到了新知识,但女朋友不理你还是开心不起来对吧。
五、参考资料
https://groups.google.com/forum/#!topic/cefglue/k-ixiAiszYg
https://code.google.com/p/cefpython/source/browse/cefpython/cef3/linux/binaries_64bit/wxpython-response.py?r=26d373f81ca9
http://blog.csdn.net/lee353086/article/details/40779471
使用C#在CEF中拦截并响应请求的更多相关文章
- Structs2 中拦截器获取请求参数
前言 环境:window 10,JDK 1.7,Tomcat 7 测试代码 package com.szxy.interceptor; import java.util.Map; import jav ...
- 说说struts2中拦截器的请求流程一(模拟大致流程)
本文可作为北京尚学堂struts2课程的学习笔记. 首先 什么是拦截器?拦截器能干什么? 拦截器,顾名思义就是拦截对象然后做操作的东西,至于是拦截谁?那自然是拦截action了.能做什么操作呢?你想让 ...
- 简单理解Struts2中拦截器与过滤器的区别及执行顺序
简单理解Struts2中拦截器与过滤器的区别及执行顺序 当接收到一个httprequest , a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标 ...
- Mock.js开发中拦截Ajax
Mock.js 是一款前端开发中拦截Ajax请求再生成随机数据响应的工具.可以用来模拟服务器响应. 优点是非常简单方便, 无侵入性, 基本覆盖常用的接口数据类型. 在我们的生产实际中,后端的接口往往是 ...
- vue中采用axios发送请求及拦截器
这几天在使用vue中axios发送get请求的时候很顺手,但是在发送post请求的时候老是在成功的回调函数里边返回参数不存在,当时就纳闷了,经过查阅资料,终于得到了解决方案,在此做一总结: 首先我们在 ...
- Fragment中onActivityResult不响应
开发中遇到Fragment中onActivityResult不响应的问题,曾经见过. 不少同学说处理方法是在与Fragment绑定的FragmentActivity中重写onActivityResul ...
- Spring 中拦截器与过滤器的区别
spring 中拦截器 与servlet 的filter 有相似之处.比如二者都是aop 编程思想的体现都能实现权限检查,日志记录等. 不同之处 使用范围不同 Filter 是Servlet 规定的. ...
- axios设置请求拦截和响应拦截
首先我们先创建axios实例 const service = axios.create({ baseURL: url, //是用于请求的服务器 URL timeout: 5000, // 请求超时时间 ...
- shiro中拦截器机制
8.1 拦截器介绍 Shiro使用了与Servlet一样的Filter接口进行扩展:所以如果对Filter不熟悉可以参考<Servlet3.1规范>http://www.iteye.com ...
随机推荐
- PageRank的java实现
一个网络(有向带权图)中节点u的PageRank的计算公式: PR(u)表示节点u的PageRank值,d为衰减因子(damping factor)或阻尼系数,一般取d=0.85,N为网络中的节点总数 ...
- c coroutine
今天看了下云风c coroutine 代码 博客,发现 coroutine 实现原理其实还比较简单,就用户态栈切换,只需要几十行汇编,特别轻量级. 具体实现 1. 创建一个coroutine: 也就 ...
- Debian8.3安装flash插件,备用~~~
debian的浏览器iceweasel默认没有安装flash播放器,flash player这坨shit,容易使浏览器崩溃,但看在线视频又不得不用这货. 有两种安装方法: 一.安装压缩包 1.先去官网 ...
- C#和.net的版本
C#1.0:OOP和CTS(delegate)C#2.0:泛型.分部类.静态类.迭代器.匿名方法.委托的协变和逆变.属性访问器可以被单独设置访问级别.可空类型.??操作符C# 3.0:Linq.lam ...
- JS获取浏览器窗口大小 获取屏幕,浏览器,网页高度宽度
网页可见区域宽:document.body.clientWidth 网页可见区域高:document.body.clientHeight 网页可见区域宽:document.body.offsetWid ...
- url带#号,微信授权,微信分享那些坑
微信授权的方法是,在项目里面配置拦截器(此处可以参考各个框架的拦截器)没有拦截器也可以,反正意思就是跳转到项目里的时候判断微信环境 如果是微信环境, 判断微信环境的方法是 var ua = windo ...
- MFC 静态文本的自绘 空心字的实现
想在对话框里,显示几个字是很简单的,只要用静态文本的输出就可以了.然而有时候我们需要显示特效的字,我们希望显示的文字就像Word里的艺术字一样,看起来美观.这时我们可以重写CStatic类.用Draw ...
- Xcode静态检查分析代码
Clang静态分析和Instruments来剖析代码有一些不同,Clang更致力于在编译的过程中通过自身的一套判断机制来找出代码中潜在的隐患. 在XCode 3.2之后的版本里,Clang已经被集 ...
- MS Sql Server
# 安装SQL2000时总是提示:以前的某个程序安装已经在安装计算机上创建挂起的文件操作 原文:https://zhidao.baidu.com/question/424367402.html # S ...
- 【Java EE 学习 79 上】【mybatis 基本使用方法】
一.简介 mybatis类似于hibernate,都是简化对数据库操作的框架,但是和hibernate不同的是,mybatis更加灵活,整体来说框架更小,这体现在它需要我们手写SQL语句,而hiber ...