CEF独立于浏览器的http请求

首先感谢:http://blog.csdn.net/foruok/article/details/50679694

经过此文章的详细说明,我成功实现了cef独立于浏览器的http请求和对reponse的处理。我的初衷是通过http的get请求缓存所有请求过的页面到本地。

以下是我的代码UrlRequestClass.h:

#ifndef URL_REQUEST_CLIENT_H
#define URL_REQUEST_CLIENT_H
#include "include/wrapper/cef_helpers.h"
#include "include/cef_urlrequest.h"
#include 
#include 
#pragma comment(lib, "urlmon.lib")
class UrlRequestCompletionCallback
{
public:
	virtual ~UrlRequestCompletionCallback(){}
	virtual void OnCompletion(CefURLRequest::ErrorCode errorCode,
		const std::string& data) = 0;
};

class UrlRequestClass :public CefURLRequestClient
{
public:
	UrlRequestClass();
	void OnRequestComplete(CefRefPtr request) OVERRIDE;

	void OnUploadProgress(CefRefPtr request,
		int64 current,
		int64 total) OVERRIDE;

	void OnDownloadProgress(CefRefPtr request,
		int64 current,
		int64 total) OVERRIDE;

	void OnDownloadData(CefRefPtr 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 callback) OVERRIDE{
		return false;
	}

	void Request(CefRefPtr cef_request);
	void Get(const std::string &url, const CefRequest::HeaderMap &headers = CefRequest::HeaderMap());
	void Post(const std::string &url, const CefRefPtr data, const CefRequest::HeaderMap &headers = CefRequest::HeaderMap());

	void SetCompletionCallback(UrlRequestCompletionCallback *callback);
private:
	CefRefPtr m_urlRequest;
	std::string m_data;
	std::ofstream *pfile;
	CRITICAL_SECTION m_cs;// = NULL;
	IMPLEMENT_REFCOUNTING(UrlRequestClass);
	DISALLOW_COPY_AND_ASSIGN(UrlRequestClass);
};

#endif

说明:

  • 请求必须在UI线程,所以构造函数有CEF_REQUIRE_UI_THREAD();
  • OnRequestComplete()是请求返回并处理成功之后的回调函数;
  • OnUploadProgress()是有上传文件时可计算当前上传进度的回调函数;
  • OnDownloadProgress()是下载文件时的下载进度回调;
  • OnDownloadData()是下载文件时调用的函数,要下载文件则需要手动填补此函数;
  • Request()函数发送封装好的Http请求;
  • Post()和Get()封装对应的请求、参数等;
  • SetCompletionCallback()设置完成请求之后的回调,在OnRequestComplete()之后触发。

UrlRequestClass.cpp文件

#include "UrlRequestClass.h"
#include 
#include 
#include 
#include 

UrlRequestClass::UrlRequestClass()
{
	CEF_REQUIRE_UI_THREAD();
	pfile = new std::ofstream();
	pfile->rdbuf()->pubsetbuf(0, 0);
	pfile->open("C:\\Users\\ffmpeg.zip", std::ios::app | std::ios::out | std::ios::binary);//文件路径+后缀
}


void UrlRequestClass::OnRequestComplete(CefRefPtr request)
{
	CEF_REQUIRE_UI_THREAD();
	pfile->close();
}

void UrlRequestClass::OnUploadProgress(CefRefPtr request, int64 current, int64 total)
{

}

void UrlRequestClass::OnDownloadProgress(CefRefPtr request, int64 current, int64 total)
{
	char szLog[128] = { 0 };
	sprintf_s(szLog, 128, "UrlRequestClass::OnDownloadProgress, current-%lld, total-%lld\r\n",
		current, total);
	OutputDebugStringA(szLog);
}

void UrlRequestClass::OnDownloadData(CefRefPtr request, const void* data, size_t data_length)
{
	CEF_REQUIRE_UI_THREAD(); 
	m_data += std::string(static_cast(data), data_length);
	if (data_length>0)
	{
		std::stringstream filstream;
		filstream.write((char *)data, data_length);
		pfile->write(filstream.str().c_str(), data_length);

	}
}

void UrlRequestClass::Request(CefRefPtr cef_request)
{
	m_urlRequest = CefURLRequest::Create(cef_request, this, NULL);
}

void UrlRequestClass::Get(const std::string &url, const CefRequest::HeaderMap &headers)
{
	CefRefPtr req = CefRequest::Create();
	req->SetURL(url);
	req->SetMethod("GET");
	req->SetHeaderMap(headers);
	Request(req);
}

void UrlRequestClass::Post(const std::string &url, const CefRefPtr data, const CefRequest::HeaderMap &headers)
{
	CefRefPtr req = CefRequest::Create();
	req->SetURL(url);
	req->SetMethod("POST");
	req->SetHeaderMap(headers);
	req->SetPostData(data);
	Request(req);
}

void UrlRequestClass::SetCompletionCallback(UrlRequestCompletionCallback *callback)
{

}

应用,在cefclient_win.cc的context的初始化之后调用:

 UrlRequestClass test;
  test.Get("https://ffmpeg.zeranoe.com/builds/win32/dev/ffmpeg-20180207-8318bf1-win32-dev.zip");

这是ffmpeg的压缩包,成功下载解压。

另外:说明一个我在写这个的过程中踩过很多次的坑:

这是我原先的文件读写函数

if (data_length>0)
	{
		std::ofstream pfile;
		std::stringstream filstream;
		filstream.write((char *)data, data_length);
		pfile.rdbuf()->pubsetbuf(0, 0);
		pfile.open("C:\\Users\\qqtest.exe", std::ios::app | std::ios::out | std::ios::binary);
		if (false == pfile.is_open())
		{
			pfile.close();
			OnDownloadData(request, data, data_length);
			//这两句原先是MessageBox(NULL,NULL,NULL,NULL);
		}
		pfile.write(filstream.str().c_str(), data_length);
		pfile.close();
	}

上面是每写一部分数据都要打开关闭文件一次,后果是除了图片格式,其他的文档如:.exe  .zip    .doc     .mp4文件下载后打开时都会出现部分数据丢失/破损的提示,多次调试发现原因是文件被其他进程打开占。

后来改为在构造函数中打开文件,中间一直写文件直到写完再关闭,解决了数据丢失的问题。

文件操作这里还是值得注意的!!!


你可能感兴趣的:(cef3,http请求,http下载)