使用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 ...
随机推荐
- web加密的基本概念
1.需求 了解web加密的一些基础概念. 2.基本概念 a.对称加密方式 对称加密方式 加密和解密用同一个密钥 不足之处是,交易双方都使用同样钥匙,安全性得不到保证.此外,每对用户每次使用对称加密算法 ...
- awk命令和grep命令的使用
1.遇到需求:用ping命令去检测系统网络延迟 跑 ping baidu.com -c 3,想要直接得到平均延迟. ping baidu.com -c 3 | grep rtt | awk -F \/ ...
- mysql 查询表结构
use information_schema; select column_name, column_type, data_type, is_nullable, column_comment from ...
- 枚举扩展方法获取枚举Description
枚举扩展方法 /// <summary> /// 扩展方法,获得枚举的Description /// </summary> /// <param name="v ...
- Django (2)
一.Django基本 程序编写 a. url.py /index/ -> func b. views.py def func(request): # 包含所有 ...
- JetBrains PyCharm 2016.2.3注册码
43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...
- WEB 用户指南 -- WEB 系统结构文档
本文描述了如何使用 WEB语言 编程.同时还包含了 WEAVE 和 TANGLE 程序的说明文档. WEB 程序 可以读取 WEB 文件,然后输出 TeX 文档 和 Pascal 程序. 使用 WEB ...
- C语言 指针小结
指针 -->指针变量 类型名 *变量名 int *point1; char *point2; 注意:*p可以直接使用,它代表指针p指向的变量,*p可以当做被指向的变量使用!~~~~ 一个变量的地 ...
- 也说python的类--基于python3.5
在面向对象的语言中,除了方法.对象,剩下的一大重点就是类了,从意义上来讲,类就是对具有相同行为对象的归纳.当一个或多个对象有相同属性.方法等共同特征的时候,我们就可以把它归纳到同一个类当中.在使用上来 ...
- 创建Hello World程序(part-1)
写在前面: 2006年,刚上大学,班上有几个计算机文盲,1分钟打二十几个字都困难,很不幸,我就是其中的一个.强烈的自尊心驱使我不停恶补,翻遍了图书馆的计算机文化基础,知耻而后勇...后来,C语言居然考 ...