一、前言

忙里偷闲,研究了一下如何在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中拦截并响应请求的更多相关文章

  1. Structs2 中拦截器获取请求参数

    前言 环境:window 10,JDK 1.7,Tomcat 7 测试代码 package com.szxy.interceptor; import java.util.Map; import jav ...

  2. 说说struts2中拦截器的请求流程一(模拟大致流程)

    本文可作为北京尚学堂struts2课程的学习笔记. 首先 什么是拦截器?拦截器能干什么? 拦截器,顾名思义就是拦截对象然后做操作的东西,至于是拦截谁?那自然是拦截action了.能做什么操作呢?你想让 ...

  3. 简单理解Struts2中拦截器与过滤器的区别及执行顺序

    简单理解Struts2中拦截器与过滤器的区别及执行顺序 当接收到一个httprequest , a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标 ...

  4. Mock.js开发中拦截Ajax

    Mock.js 是一款前端开发中拦截Ajax请求再生成随机数据响应的工具.可以用来模拟服务器响应. 优点是非常简单方便, 无侵入性, 基本覆盖常用的接口数据类型. 在我们的生产实际中,后端的接口往往是 ...

  5. vue中采用axios发送请求及拦截器

    这几天在使用vue中axios发送get请求的时候很顺手,但是在发送post请求的时候老是在成功的回调函数里边返回参数不存在,当时就纳闷了,经过查阅资料,终于得到了解决方案,在此做一总结: 首先我们在 ...

  6. Fragment中onActivityResult不响应

    开发中遇到Fragment中onActivityResult不响应的问题,曾经见过. 不少同学说处理方法是在与Fragment绑定的FragmentActivity中重写onActivityResul ...

  7. Spring 中拦截器与过滤器的区别

    spring 中拦截器 与servlet 的filter 有相似之处.比如二者都是aop 编程思想的体现都能实现权限检查,日志记录等. 不同之处 使用范围不同 Filter 是Servlet 规定的. ...

  8. axios设置请求拦截和响应拦截

    首先我们先创建axios实例 const service = axios.create({ baseURL: url, //是用于请求的服务器 URL timeout: 5000, // 请求超时时间 ...

  9. shiro中拦截器机制

    8.1 拦截器介绍 Shiro使用了与Servlet一样的Filter接口进行扩展:所以如果对Filter不熟悉可以参考<Servlet3.1规范>http://www.iteye.com ...

随机推荐

  1. 疯狂了!当游戏爱上MongoDB会怎么样???

    导读 前端时间魔兽这个电影我相信大家都看过了哈,作为一个码农,有时候我也会去思考魔兽世界这个游戏背后他的一些设计和实现,比如他用什么数据库.当然真正用什么数据库这个我是不确定的,我们今天的主题是当游戏 ...

  2. C#多线程--信号量(Semaphore)

    百度百科:Semaphore,是负责协调各个线程, 以保证它们能够正确.合理的使用公共资源.也是操作系统中用于控制进程同步互斥的量. Semaphore常用的方法有两个WaitOne()和Releas ...

  3. bootstrap的table调用本列ID

    我们是用json解析数据. 后台传送data数据~ String data = JSON.toJSONString(baseInfoService.list());request.setAttribu ...

  4. 解决Unsupported major.minor version 51.0错误

    解决Unsupported major.minor version 51.0错误使用jdk6运行项目时发生了Unsupported major.minor version 51.0错误.经过网上搜索发 ...

  5. Delphi Code Editor 之 编辑器选项

    Delphi Code Editor 之 编辑器选项 可从Code Editor的右键菜单中选择“Properties”菜单项来查看编辑器选项.也可以从主菜单[Tools | Editor Optio ...

  6. markdown博文测试

    一级标题 二级标题 正文 三级标题 C代码: // code #include <stdio.h> int main() { printf("Hello, World!\n&qu ...

  7. js_跨域

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  8. Servlet调用过程

    (1)在浏览器输入地址,浏览器先去查找hosts文件,将主机名翻译为ip地址,如果找不到就再去查询dns服务器将主机名翻译成ip地址. (2)浏览器根据ip地址和端口号访问服务器,组织http请求信息 ...

  9. MongoDB学习笔记

    MongoDB的学习目标(v.3.4.0) 1.MongoDB的概念,非关系型数据库NOSQL 2.学会MongoDB的搭建 3.熟悉MongoDB使用 最基本的文档的读写更新删除 各种不同类型的索引 ...

  10. CC2540自己的配置文件

    首先要指出,字段属性有notify的不能同时有read,write属性,别问哥,哥也不知道,反正我做的就不能notify,只能read,write. 分享的程序段第一字段有notify属性,第二字段r ...