使用CEF類庫處理HTTP請求


當我們基於CEF開發應用時,可能會有URL請求處理的需求,比如HTTP下載或上傳,此時可以利用CEF提供的類庫來完成,而不必自己實現或引入其它第三方的類庫。

在CEF里為URL Request設計了兩組類,一組用於執行網絡請求,一組代表請求數據。

URLRequest

CefURLRequest是執行URL請求的類(接口),對應的頭文件是cef_urlrequest.h,實現則在libcef/common/urlrequest_impl.cc文件中。

CefURLRequest類的靜態方法Create()可以創建並執行一個URL請求。它的原型如下:

?
1
2
3
4
5
<code> static CefRefPtr<cefurlrequest> Create(
       CefRefPtr<cefrequest> request,
       CefRefPtr<cefurlrequestclient> client,
       CefRefPtr<cefrequestcontext> request_context);
</cefrequestcontext></cefurlrequestclient></cefrequest></cefurlrequest></code>

第一個參數,類型是CefRequest,代表一個URL請求,CEF庫內部已經實現了,后面會講到。

第二個參數,類型是CefURLRequestClient,用於接收服務器返回的狀態和數據,需要我們自己繼承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 對象:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<code>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);
</cefrequest></cefpostdataelement></cefpostdata></code>

與一個請求相關的類和接口,都在cef_request.h中,實現在request_impl.cc中。這些類都有靜態的Create方法,可以返回一個代表具體實例的接口,然后就可以接口的方法來定制實例對象,定制后的對象就可以用於URL請求了。

剛才的代碼片段演示了如何構造一個CefRequest對象,其中用到了下面的類(接口):

CefRequest,代表了一個URL請求 CefPostData,管理要通過請求發送的數據,它內部維護了多個CefPostDataElement,每個CefPostDataElement代表了一個要發送的數據元素 CefPostDataElement,代表發送的數據,提供了一些接口,可以關聯到文件,也可以直接發送字節

想了解至於這些類的接口,打開頭文件看看吧。

實現CefURLRequestClient接口

CefURLRequestClient接口的實現可以很簡單,我實現了一個簡單的UrlRequestClient類。

UrlRequestClient.h如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<code>#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
</cefurlrequest></cefpostdata></cefrequest></cefauthcallback></cefurlrequest></cefurlrequest></cefurlrequest></cefurlrequest></string></code>

UrlRequestClient.cpp內容如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<code>#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 >(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 ;
}
</cefrequest></cefpostdata></cefrequest></cefrequest></ const ></cefurlrequest></cefurlrequest></cefurlrequest></cefurlrequest></windows.h></code>

UrlRequestClient類可以發起URL請求並處理響應。它的用法類似下面這樣(注意要在Browser進程的UI線程使用):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<code> // Get() test
UrlRequestClient *client = new UrlRequestClient( new PrintUrlReqCallback);
std::string url( "http://www.baidu.com" );
client->Get(url);
 
// Request() test
CefRefPtr<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() test
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" ));
( new UrlRequestClient( new PrintUrlReqCallback))->Post( "http://xxx.com/hello" , data, headers);
</cefpostdataelement></cefpostdata></cefrequest></code>

就這樣吧。


免責聲明!

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



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