標籤:tco 自己 實現 clu markdown int 原創 XML 標頭檔
當我們基於CEF開發應用時,可能會有URL請求處理的需求,比方HTTP下載或上傳。此時能夠利用CEF提供的類庫來完畢,而不必自己實現或引入其他第三方的類庫。
在CEF裡為URL Request設計了兩組類,一組用於運行網路請求,一組代表請求資料。
foruok原創。轉載請保留出處或關注foruok的訂閱號“程式視界”來聯絡foruok。
URLRequest
CefURLRequest是運行URL請求的類(介面),相應的標頭檔是cef_urlrequest.h,實現則在libcef/common/urlrequest_impl.cc檔案裡。
CefURLRequest類的靜態方法Create()能夠建立並運行一個URL請求。它的原型例如以下:
static CefRefPtr<CefURLRequest> Create( CefRefPtr<CefRequest> request, CefRefPtr<CefURLRequestClient> client, CefRefPtr<CefRequestContext> request_context);
第一個參數,類型是CefRequest,代表一個URL請求。CEF庫內部已經實現了,後面會講到。
第二個參數。類型是CefURLRequestClient,用於接收server返回的狀態和資料,須要我們自己繼承CefURLRequestClient介面實現一個非抽象類別。
後面有了。
第三個參數。CefRequestContext,為NULL時內部會自己建立一個合適的Context。不為NULL時就用傳入的Context。
Create方法會依據當前是Browser進程還是Renderer進程來建立相應的URLRequest類,CefBrowserURLRequest(browser_urlrequest_impl.h/.cc)或CefRenderURLRequest(render_urlrequest_impl.h/.cc)。
這麼分析下來,我們要進行URL請求,實際上要做的工作就是:
- 構造一個CefRequest,代表我們的請求
- 寫一個類實現CefURLRequestClient介面來處理響應。
- 調用CefURLRequest::Create()建立一個URL請求處理對象
構造Request
CefRequest類代表了一個URL請求。它裡面能夠配置方法、URL、頭部、上傳的資料等。以下的程式碼片段示範了怎樣構造一個 CefRequest 對象:
CefRefPtr<CefPostData> data = CefPostData::Create();CefRefPtr<CefPostDataElement> element = CefPostDataElement::Create();const char szData[] = "Hello World!";element->SetToBytes(sizeof(szData) - 1, (const void*)szData);data->AddElement(element);CefRequest::HeaderMap headers;headers.insert(std::make_pair("Content-Type", "text/plain"));headers.insert(std::make_pair("Accept", "text/plain"));CefRefPtr<CefRequest> req = CefRequest::Create();req->SetMethod("POST");req->SetURL("http://xxx.net");req->SetHeaderMap(headers);req->SetPostData(data);
與一個請求相關的類和介面,都在cef_request.h中,實如今request_impl.cc中。
這些類都有靜態Create方法。能夠返回一個代表詳細執行個體的介面。然後就能夠介面的方法來定製執行個體對象,定製後的對象就能夠用於URL請求了。
剛才的程式碼片段示範了怎樣構造一個CefRequest對象。當中用到了以下的類(介面):
- CefRequest,代表了一個URL請求
- CefPostData,管理要通過請求發送的資料。它內部維護了多個CefPostDataElement。每一個CefPostDataElement代表了一個要發送的資料元素
- CefPostDataElement,代表發送的資料。提供了一些介面。能夠關聯到檔案,也能夠直接發送位元組
想瞭解至於這些類的介面,開啟標頭檔看看吧。
實現CefURLRequestClient介面
CefURLRequestClient介面的實現能夠非常easy。我實現了一個簡單的UrlRequestClient類。
UrlRequestClient.h例如以下:
#ifndef URL_REQUEST_CLIENT_H#define URL_REQUEST_CLIENT_H#include <string>#include "include/cef_urlrequest.h"#include "include/wrapper/cef_helpers.h"class UrlRequestCompletionCallback{public: virtual ~UrlRequestCompletionCallback(){} virtual void OnCompletion(CefURLRequest::ErrorCode errorCode, const std::string& data) = 0;};class UrlRequestClient : public CefURLRequestClient{public: UrlRequestClient() : m_callback(0) { CEF_REQUIRE_UI_THREAD(); } UrlRequestClient(UrlRequestCompletionCallback *callback) : m_callback(callback) { CEF_REQUIRE_UI_THREAD(); } // //interfaces of CefURLRequestClient // void OnRequestComplete(CefRefPtr<CefURLRequest> request) OVERRIDE; void OnUploadProgress(CefRefPtr<CefURLRequest> request, int64 current, int64 total) OVERRIDE; void OnDownloadProgress(CefRefPtr<CefURLRequest> request, int64 current, int64 total) OVERRIDE; void OnDownloadData(CefRefPtr<CefURLRequest> request, const void* data, size_t data_length) OVERRIDE; bool GetAuthCredentials(bool isProxy, const CefString& host, int port, const CefString& realm, const CefString& scheme, CefRefPtr<CefAuthCallback> callback) OVERRIDE{ return false; } void Request(CefRefPtr<CefRequest> cef_request); void Get(const std::string &url, const CefRequest::HeaderMap &headers = CefRequest::HeaderMap()); void Post(const std::string &url, const CefRefPtr<CefPostData> data, const CefRequest::HeaderMap &headers = CefRequest::HeaderMap()); void SetCompletionCallback(UrlRequestCompletionCallback *callback) { m_callback = callback; }private: UrlRequestCompletionCallback *m_callback; CefRefPtr<CefURLRequest> m_urlRequest; std::string m_data; IMPLEMENT_REFCOUNTING(UrlRequestClient); DISALLOW_COPY_AND_ASSIGN(UrlRequestClient);};class PrintUrlReqCallback : public UrlRequestCompletionCallback{public: void OnCompletion(CefURLRequest::ErrorCode errorCode, const std::string& data);};#endif
UrlRequestClient.cpp內容例如以下:
#include "UrlRequestClient.h"#include <Windows.h>void UrlRequestClient::OnRequestComplete(CefRefPtr<CefURLRequest> request){ CEF_REQUIRE_UI_THREAD(); if (m_callback) { m_callback->OnCompletion(request->GetRequestError(), m_data); }}void UrlRequestClient::OnUploadProgress(CefRefPtr<CefURLRequest> request, int64 current, int64 total){}void UrlRequestClient::OnDownloadProgress(CefRefPtr<CefURLRequest> request, int64 current, int64 total){ char szLog[128] = { 0 }; sprintf_s(szLog, 128, "UrlRequestClient::OnDownloadProgress, current-%lld, total-%lld\r\n", current, total); OutputDebugStringA(szLog);}void UrlRequestClient::OnDownloadData(CefRefPtr<CefURLRequest> request, const void* data, size_t data_length){ m_data += std::string(static_cast<const char*>(data), data_length);}void UrlRequestClient::Request(CefRefPtr<CefRequest> cef_request){ m_urlRequest = CefURLRequest::Create(cef_request, this, NULL);}void UrlRequestClient::Get(const std::string &url, const CefRequest::HeaderMap &headers /*= CefRequest::HeaderMap()*/){ CefRefPtr<CefRequest> req = CefRequest::Create(); req->SetURL(url); req->SetMethod("GET"); req->SetHeaderMap(headers); Request(req);}void UrlRequestClient::Post(const std::string &url, const CefRefPtr<CefPostData> data, const CefRequest::HeaderMap &headers /*= CefRequest::HeaderMap()*/){ CefRefPtr<CefRequest> req = CefRequest::Create(); req->SetURL(url); req->SetMethod("POST"); req->SetHeaderMap(headers); req->SetPostData(data); Request(req);}//// for test//void PrintUrlReqCallback::OnCompletion(CefURLRequest::ErrorCode errorCode, const std::string& data){ char szLog[128] = { 0 }; sprintf_s(szLog, 128, "PrintUrlReqCallback::OnCompletion, errorCode = %d, data.len = %d, data:\r\n", errorCode, data.length()); OutputDebugStringA(szLog); delete this;}
UrlRequestClient類能夠發起URL請求並處理響應。它的使用方法相似以下這樣(注意要在Browser進程的UI線程使用):
// Get() testUrlRequestClient *client = new UrlRequestClient(new PrintUrlReqCallback);std::string url("http://www.baidu.com");client->Get(url);// Request() testCefRefPtr<CefRequest> req = CefRequest::Create();req->SetMethod("GET");req->SetURL("http://www.csdn.net");CefRequest::HeaderMap headers;headers.insert(std::make_pair("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"));headers.insert(std::make_pair("Accept-Encoding", "gzip,deflate,sdch"));headers.insert(std::make_pair("Accept-Language", "en,zh"));req->SetHeaderMap(headers);(new UrlRequestClient(new PrintUrlReqCallback))->Request(req);// Post() testCefRefPtr<CefPostData> data = CefPostData::Create();CefRefPtr<CefPostDataElement> element = CefPostDataElement::Create();const char szData[] = "Hello World!";element->SetToBytes(sizeof(szData) - 1, (const void*)szData);data->AddElement(element);CefRequest::HeaderMap headers;headers.insert(std::make_pair("Content-Type", "text/plain"));headers.insert(std::make_pair("Accept", "text/plain"));(new UrlRequestClient(new PrintUrlReqCallback))->Post("http://xxx.com/hello", data, headers);
就這樣吧。
關於CEF裡的線程,能夠參考:http://blog.csdn.net/foruok/article/details/50674141。
關於進程,能夠參考:http://blog.csdn.net/foruok/article/details/50621751。
其他參考文章詳見我的專欄:【CEF與PPAPI開發】。
使用CEF類庫處理HTTP請求