使用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();
        }
    }

 

響應長度已知的情況:

 1         void handler_GetResponseHeaders(object sender, Chromium.Event.CfxGetResponseHeadersEventArgs e)
 2         {
 3             e.ResponseLength = Encoding.UTF8.GetBytes("<html><body><h1>Hello CEF</h1></body></html>").Length;
 4             e.Response.MimeType = "text/html";
 5             e.Response.Status = 200;
 6         }
 7 
 8         void handler_ReadResponse(object sender, Chromium.Event.CfxReadResponseEventArgs e)
 9         {
10                 byte[] data = Encoding.UTF8.GetBytes("<html><body><h1>Hello CEF</h1></body></html>");
11                 e.BytesRead = data.Length;
12                 Marshal.Copy(data, 0, e.DataOut, data.Length);
13                 e.SetReturnValue(true);
14         }

最終效果如下:

 綜上所述,雖然學到了新知識,但女朋友不理你還是開心不起來對吧。

 

五、參考資料

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM